# When do the lights blink?

Imagine you have two lights. These lights blink on and off at a specific rate:

Light 0: Delay 0ms and then blink every 1000ms
Light 1: Delay 500ms and then blink every 1000ms


Let's simulate these lights for the first 2000ms:

0ms:    Light 0 on
500ms:  Light 1 on
1000ms: Light 0 off
1500ms: Light 1 off
2000ms: Light 0 on


# The challenge

Given a list of ordered pairs representing the timing for lights, write a program or function to output the sequence for when they blink.

### Input

The input should be in the following format:

TimeToSimulate
Light0Delay,Light0Period
Light1Delay,Light1Period
...


In this format, the example above would be:

2000
0,1000
500,1000


### Output

The output should be a series of ordered triples:

Time,LightNum,LightStatus


LightStatus is a truthy value if the light turns on and a falsy value if the light turns off.

The output from the above example would be:

0,0,True
500,1,True
1000,0,False
1500,1,False
2000,0,True


If two lights blink at the same time, the light with the lower number should display first in the output.

### Other stuff

• The input and output formats aren't strict
• Code shouldn't produce any errors
• The solution shouldn't rely on race conditions
• No standard loopholes
• This is , so shortest solution wins!

### Test cases

Input:

2000
0,1000
500,1000

Output:

0,0,True
500,1,True
1000,0,False
1500,1,False
2000,0,True

----

Input:

2
0,1
0,1

Output:

0,0,True
0,1,True
1,0,False
1,1,False
2,0,True
2,1,True

----

Input:

500
100,50
200,100
300,150

Output:

100,0,True
150,0,False
200,0,True
200,1,True
250,0,False
300,0,True
300,1,False
300,2,True
350,0,False
400,0,True
400,1,True
450,0,False
450,2,False
500,0,True
500,1,False

----

Input:

1000
23,345
65,98
912,12
43,365

Output:

23,0,True
43,3,True
65,1,True
163,1,False
261,1,True
359,1,False
368,0,False
408,3,False
457,1,True
555,1,False
653,1,True
713,0,True
751,1,False
773,3,True
849,1,True
912,2,True
924,2,False
936,2,True
947,1,False
948,2,False
960,2,True
972,2,False
984,2,True
996,2,False


var QUESTION_ID=137465,OVERRIDE_USER=41505;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

• How much output is enough? – aschepler Aug 3 '17 at 22:57
• @aschepler What do you mean? The input specifies an amount of time to "simulate" – Daniel M. Aug 3 '17 at 22:58

# JavaScript, 98 97 bytes

a=>b=>[...Array(a+1)].map((_,i)=>b.map((d,j)=>d[0]--||c.push([i,j,d[d[0]=d[1]-1,2]^=1])),c=[])&&c


Try it online

Saved a byte thanks to Shaggy - use currying input syntax.

• Save a byte with currying: a=>b=>. – Shaggy Aug 3 '17 at 23:08
• @Shaggy. You're so fast, I was preparing an edit. – user72349 Aug 3 '17 at 23:10
• Rule of thumb: if there are 2 inputs, always curry! – Shaggy Aug 3 '17 at 23:11

# Python 2, 93 bytes

lambda t,l:sorted(sum([zip(range(x[0],-~t,x[1]),[i]*-~t,[1,0]*t)for i,x in enumerate(l)],[]))


Try it online!

# Jelly,  26  25 bytes

Ḣrm⁸ð€µ;€€"J;"J$€€ẎẎḂ0¦€Ṣ  A dyadic link taking a list of delay, period number-lists and a time-frame number and returning a list of time, light, action integers. The lights are 1-indexed and 0 represents the 'off' action, while 1 represents the 'on' action. Try it online! ### How? Ḣrm⁸ð€µ;€€"J;"J$€€ẎẎḂ0¦€Ṣ - Link: [[delay, period],...], time-frame
ð€                    - for €ach [delay, period]:
Ḣ                         -   head (get the delay and modify the item to [period])
r                        -   inclusive range to time-frame = [delay,delay+1,...,time-frame]
⁸                      -   chain's left argument = [period]
m                       -   modulo slice = [delay, delay+period, delay+2*period, ...]
µ                   - monadic chain separation, call that v
J              - range(length(v)) = [1,2,...,nLights]
"               - zip with:
;€€                -   concatenate for €ach for €ach (add light indexes to times)
$€€ - last two links as a monad for €ach for €ach: J - range (length(switch-times-for-a-light)) " - zip with: ; - concatenation (i.e. append a 1-based index) ẎẎ - tighten & tighten again (flatten by 2 to a list of triples) |€ - sparse application of (for €ach): 0 - ...to indexes: 0 (=last entry) Ḃ - ...action: modulo by 2 (even appended indexes ->0s; odds -> 1s) Ṣ - sort the resulting list of triples  # Python 2, 206 214 bytes • Added eight bytes to comply with the rules (taking input via stdin). Q=input();D,T=Q[0],[map(int,q.split(","))for q in Q[1:]];O,l=[],len(T) for j in range(l): t,b=T[j][0],9>8 while t<=int(D):O+="%0*d,%0*d,%s"%(len(D),t,len(str(l)),j,b),;b=not b;t+=T[j][1] print"\n".join(sorted(O))  Try it online! This code generates an unordered lists containing each light's switching times, pads those times and the light identifier, sorts said list and outputs it. • By standard rules you must take input you cannot expect it to pre-exist in a variable. You'll probably find that using input() will allow you to cut they byte-count down too (no string parsing will be required since Python 2's input() is eval(raw_input())) :). – Jonathan Allan Aug 4 '17 at 0:13 • ...also if you use numbers rather than strings in O they'll sort, which would probably also cut the byte count, – Jonathan Allan Aug 4 '17 at 0:16 • @JonathanAllan Thanks for noticing the rule discrepency; I will not incorporate your suggestions as there is a significantly shorter Python 2 answer by now. – Jonathan Frech Oct 22 '17 at 21:15 # Perl 5, 106 + 1 (-n) = 107 bytes ($a[$i],$b[$i++])=eval for<>;for$i(0..$_){for(0..$#a){$a[$_]+=$b[$_],say"$i,$_,".($s[$_]^=1)if$i==$a[$_]}}  Try it online! # Haskell, 121 bytes import Data.List t!l=sort$(zip[0..]l)>>=takeWhile(\(a,_,_)->a<=t).(\(i,(d,w))->iterate(\(t,i,s)->(t+w,i,not s))(d,i,2>1))


Try it online.

This is the program I started from:

import Data.List

type LightId = Int
type Time = Int
type State = Bool
type LightEvent = (Time, LightId, State)

lightSimulation :: Time -> Time -> [(Time, State)]
lightSimulation delay interval = iterate step (delay, True)
where step (time, state) = (time+interval, not state)

addId :: LightId -> (Time, State) -> LightEvent
addId id (t, s) = (t, id, s)

simulate :: Time -> [(Time, Time)] -> [LightEvent]
simulate timeLimit lights = sort $concatMap lightSim (zip [0..] lights) where withinTimeLimit = ((<=timeLimit) . fst) lightSims (id, (delay, interval)) = map (addId id)$ takeWhile withinTimeLimit (lightSimulation delay interval)


And before final golfing I has shortened it to:

import Data.List

light (id,(delay,interval)) = iterate step (delay, id, True)
where step (time, id, state) = (time+interval, id, not state)

simulate timeLimit lights = sort $concatMap lightSims (zip [0..] lights) where lightSims l = takeWhile(\(a,b,c)->a<=timeLimit)$light l


# Röda, 10587 85 bytes

{|t|enum|[([_+_]*(t-_1[0]+1))()|enum|(_+_)]|{[[_+_4,_3,_4//_2%2=0]]if[_4%_2=0]}|sort}


Try it online!

Explanation:

{|t| /* Declare a lambda with one parameter */
/* The input stream contains arrays */
enum| /* For each array in the input, push an ascending number after it */
/* [1] (for stream content in this point, see below) */
[ /* For each array-number pair in the stream: */
(
[_+_] /* Create a copy of the array with the number as the last element */
*(t-_1[0]+1) /* Create copies of the array for every ms simulated */
)()| /* Push all copies to the stream */
enum| /* After each copy, push an ascending number to the stream */
(_+_) /* Append the number to each array before */
]|
/* [2] (for stream content in this point, see below) */
{
/* Push an on or off event to the stream: */
[[
_+_4,      /* delay + time = actual time */
_3,        /* light-id */
_4//_2%2=0 /* does the light go on or off? */
]]
if[_4%_2=0] /* if the light goes on or off (time%period=0) */
}|
/* [3] (for stream content in this point, see below) */
sort /* Sort the events */
}


The stream contains at point [1] values in the following order:

[delay, period], light-id
_1[0]  _1[1]    _2


The stream contains at point [2] values in the following order:

delay, period, light-id, time
_1     _2      _3        _4


The stream contains at point [3] arrays with the following structure:

[time, light-id, on_or_off]