I thought that Nest
or some variation on it might work well for this. There are many other ways, the simplest of which is probably just a Do
loop, but I don't use Nest
and Fold
nearly as much as I'd like.
Basically, the first argument is a function to be applied to the last output. I have it test to see whether the Mod[currentTime, 115]
is less than or equal to 60 seconds. If it is, I reached the stoplight while it was green and I can add the time it takes to the next light to the list. If it's over 60 seconds, I reached the stoplight while it was red and must add the time until it's green again (115 seconds minus that number) to the list while not incrementing the distance. Each time the Nest
executes, this function returns a pair of numbers {time, distance}
.
The second argument just says start at time = 0
and distance = 0
.
The third argument queries the distance portion of the most recent output. If it's less than 10 miles, perform the nest one more time.
Note that I have it set up to take a velocity in mph, and it returns a list of times and distances in seconds and miles, respectively. If you want it to work in hours and miles (or better yet, meters and seconds!) it shouldn't be too difficult to change.
dtlist[v_] :=
NestWhileList[
If[
Mod[#[[1]], 115] <= 60,
{#[[1]] + 0.5/(v/3600), #[[2]] + 0.5},
{#[[1]] + 115 - Mod[#[[1]], 115], #[[2]]}
]&,
{0, 0},
#[[2]] < 10 &
]
ListLinePlot[
dtlist /@ (10 Range[6]),
AxesLabel -> {"Time (s)", "Distance (miles)"}.
PlotLegends -> Placed[
ToString[#] <> " mph" & /@ (10 Range[6]),
{Scaled[{1.01, 0}], {1, 0}}
]
]
Manipulate[
ListLinePlot[
dtlist[v],
AxesLabel -> {"Time (s)", "Distance (miles)"}
],
{{v, 30}, 1, 120}
]


Interestingly, a car travelling at 30 mph does not pass straight through all of the lights. It reaches the 1.5 mile marker at 180 seconds, at which time the light is red. A car travelling 31.3 mph will, however, pass through all of the lights without stopping.
EDIT:
This code avoids any magic numbers (aside from the conversion of mph to miles/second, I suppose). Note that v
is the velocity in mph, td
is the total distance in miles, spacing
is the spacing between stoplights in miles, greenTime
is the length of a green light in seconds, and redTime
is the length of a red light in seconds. Both of these functions assume the timer starts at the beginning of a green light.
dtlist2[v_, td_, spacing_, greenTime_, redTime_] :=
Module[
{totTime = greenTime + redTime},
NestWhileList[
If[
Mod[#[[1]], totTime] <= greenTime,
{#[[1]] + spacing/(v/3600), #[[2]] + spacing},
{#[[1]] + (totTime) - Mod[#[[1]], (totTime)], #[[2]]}
] &,
{0, 0},
#[[2]] < td &
]
]