Github Messenger

Goal: This goal to take a string and output how many contributions should be made on which days in order to display a message.

Specification

• Input
• Support letters plus space (i.e. [A-Za-z ] )
• Space is a blank 3X7
• The letters are defined in this 5x7 DOT Matrix font provided below
• The size of each letter is the minimum bounding rectangle (e.g. l = 3x7, e = 5x5)
• Coloring
• There are 5 colors C0, C1, C2, C3, C4
• CX requires Y contributions with 3X <= y < 3(X+1)
• Letters should alternate between C1 and C2
• Spaces have no color
• Each letter size should overlap exactly 1 column with adjacent letters
• If a cell has more than 1 color then use C3
• Dot Matrix
• The dot matrix is Github's contribution history graph
• If today is Monday, May 1st, 2017:
 4-30    5-07    5-15
[5-01]   5-08    5-16
5-02    5-09     .
5-03    5-10     .
5-04    5-12     .
5-05    5-13
5-06    5-14

• Output
• Flexible on how this is given
• (x, y) pairs
• x is a date greater than or equal to the current date
• y is the number of contributions to be made on the date, x
• Should be in chronological order (so I can fill in my calendar)
• If for each date, x, the given y contributions are made, the input message should show up on the Github graph (with correct coloring)
• The first date should the earliest possible
• Scoring
• Shortest program/function in bytes wins

Alphabet

Created by sylvan.black under CC

Test Cases

For these test cases, assume the current date is May 25th, 2017.

Input -> Output
-----    ------
l        5-28-17, 3
6-3-17, 3
6-4-17, 3
6-5-17, 3
6-6-17, 3
6-7-17, 3
6-8-17, 3
6-9-17, 3
6-10-17, 3
6-17-17, 3

He       5-28-17, 3
5-29-17, 3
5-30-17, 3
5-31-17, 3
6-1-17, 3
6-2-17, 3
6-3-17, 3
6-7-17, 3
6-14-17, 3
6-21-17, 3
6-25-17, 3
6-26-17, 3
6-27-17, 3
6-28-17, 9
6-29-17, 9
6-30-17, 9
7-1-17, 3
7-4-17, 6
7-6-17, 6
7-8-17, 6
7-11-17, 6
7-13-17, 6
7-15-17, 6
7-18-17, 6
7-20-17, 6
7-22-17, 6
7-26-17, 6
7-27-17, 6

o W      5-31-17, 3
6-1-17, 3
6-2-17, 3
6-6-17, 3
6-10-17, 3
6-13-17, 3
6-17-17, 3
6-20-17, 3
6-24-17, 3
6-28-17, 3
6-29-17, 3
6-30-17, 3
7-9-17, 6
7-10-17, 6
7-11-17, 6
7-12-17, 6
7-13-17, 6
7-14-17, 6
7-22-17, 6
7-26-17, 6
7-27-17, 6
7-28-17, 6
8-5-17, 6
8-6-17, 6
8-7-17, 6
8-8-17, 6
8-9-17, 6
8-10-17, 6
8-11-17, 6

• Is C4 ever used? Commented May 30, 2017 at 15:01
• @FryAmTheEggman It is not, but I included it to avoid confusion because Github displays 5 colors in the legend. Commented May 30, 2017 at 15:04
• How strict/loose are you on date output format? Commented May 30, 2017 at 15:33
• @StephenS It is flexible, as long as it is human readable (e.g. May 20th, 2017: 3, (3,"20/5/17") ) Commented May 30, 2017 at 15:36
• Where did you find that contribution table? Commented May 30, 2017 at 16:44

JavaScript (ES6), 743 bytes

s=>(n=y=>d.setDate(d.getDate()+y),d=new Date,(h=d.getDay())&&n(7-h),r={},i=0,[...s].map(c=>{c<"!"?n(14):([...parseInt("jn4x733nx8gjw6nhricv6nx8dpz2vilui81vikl7b4nhridnzvgc1svznx8dji8g16fkg0vgc6341vg38oe9vh669ofvgm1dvjnhricvyvikl7aonhrjrjxvikmm29m0rqqp2nqmi6o0vbnf6dav2t14e4vbnjqpqs0g34o3tlqqwdso43oixtg1uyt8vvgddxn2hizrn2ahizrmdbhj4suq4gtytq8wgshvtzyvgc4mq7gzhwhz4g15ymf4vg72q9snx7r2f4jmffjm7jm5gavjhizrn2mjmkh3wogsgmianjm5gavcgwxpc3mhvni2kijhgqujjj8mcsgsjhgslnihw2cx75iqyv1cuhwdrh5d".substr((c.charCodeAt()-(c>""?71:65))*7,7),36).toString(2).slice(1).replace(/(0{7})+$/,"")].map(b=>(+b&&(r[+d]=r[+d]?9:i%2?6:3),n(1))),i++,n(-7))}),Object.keys(r).map(k=>[k,r[k]]).sort((i,j)=>i[0]-j[0]>0?1:-1).map(i=>[(new Date(+i[0])+"").slice(4,15),i[1]]))  Output is an array of 2-item arrays in the form [dateString, contribs]. The snippet below shows how that can be formatted into being more readable. Un-Golfed s=>( n=y=>d.setDate(d.getDate()+y), d=new Date, (h=d.getDay()) && n(7-h), r={}, i=0, [...s].map(c=>{ c<"!" ? n(14) : ( [...parseInt("<...>".substr((c.charCodeAt()-(c>""?71:65))*7,7),36).toString(2).slice(1).replace(/(0{7})+$/,"")].map(b=>(
+b && (r[+d] = r[+d] ? 9 : i%2?6:3),
n(1)
)),
i++,
n(-7)
)
}),
Object.keys(r)
.map(k=>[k,r[k]])
.sort((i,j)=>i[0]-j[0] > 0 ? 1 : -1)
.map(i => [ (new Date(+i[0])+"").slice(4,15), i[1] ])
)


Where <...> represents the 364-byte string of characters that I created to encode each letter's dot matrix form.

Explanation

The encoded string:

jn4x733nx8gjw6nhricv6nx8dpz2vilui81vikl7b4nhridnzvgc1svznx8dji8g16fkg0vgc6341vg38oe9vh669ofvgm1dvjnhricvyvikl7aonhrjrjxvikmm29m0rqqp2nqmi6o0vbnf6dav2t14e4vbnjqpqs0g34o3tlqqwdso43oixtg1uyt8vvgddxn2hizrn2ahizrmdbhj4suq4gtytq8wgshvtzyvgc4mq7gzhwhz4g15ymf4vg72q9snx7r2f4jmffjm7jm5gavjhizrn2mjmkh3wogsgmianjm5gavcgwxpc3mhvni2kijhgqujjj8mcsgsjhgslnihw2cx75iqyv1cuhwdrh5d


Each 7 characters is a base-36 encoded binary number that contains the mapping for the character at that index. The binary form always has a leading 1 in order to preserve the leading 0s. For example, an uppercase T maps to nqmi6o0, which converts to 1100 00001000 00011111 11100000 01000000. Skipping the leading 1, each bit is one day. Most numbers have 5 columns/weeks, so the numbers with less than 5 columns have one or two sets of 7 trailing zeros that are later removed before parsing (.replace(/(0{7})+$/,"")). This keeps all encoded strings the same length, removing the need for delimiters. There's probably still more ways to improve upon this, especially with compressing the letter mappings further, so feel free to share any ideas. Binary format of the letter mappings (JS syntax, prefixed with 0b), can be found here. Basic Snippet f= s=>(n=y=>d.setDate(d.getDate()+y),d=new Date,(h=d.getDay())&&n(7-h),r={},i=0,[...s].map(c=>{c<"!"?n(14):([...parseInt("jn4x733nx8gjw6nhricv6nx8dpz2vilui81vikl7b4nhridnzvgc1svznx8dji8g16fkg0vgc6341vg38oe9vh669ofvgm1dvjnhricvyvikl7aonhrjrjxvikmm29m0rqqp2nqmi6o0vbnf6dav2t14e4vbnjqpqs0g34o3tlqqwdso43oixtg1uyt8vvgddxn2hizrn2ahizrmdbhj4suq4gtytq8wgshvtzyvgc4mq7gzhwhz4g15ymf4vg72q9snx7r2f4jmffjm7jm5gavjhizrn2mjmkh3wogsgmianjm5gavcgwxpc3mhvni2kijhgqujjj8mcsgsjhgslnihw2cx75iqyv1cuhwdrh5d".substr((c.charCodeAt()-(c>""?71:65))*7,7),36).toString(2).slice(1).replace(/(0{7})+$/,"")].map(b=>(+b&&(r[+d]=r[+d]?9:i%2?6:3),n(1))),i++,n(-7))}),Object.keys(r).map(k=>[k,r[k]]).sort((i,j)=>i[0]-j[0]>0?1:-1).map(i=>[(new Date(+i[0])+"").slice(4,15),i[1]]))

I.value="Hello World";
(I.oninput=_=>O.innerHTML = f(I.value).map(e=>e.join(": ")).join("\n"))();
<input id="I">
<pre id="O">`

Interactive example

Using the library cal-heatmap, I created an interactive heatmap of the dates that are output. This was used to test everything while working, and it just looks plain neat.

• The interactive example is really awesome. Nice job! Commented Jun 8, 2017 at 2:57
• Oh god, someone actually did this! Nice! Commented Jun 8, 2017 at 15:06
• Thanks guys! This was a really cool challenge, I wish more people would come attempt it. I've edited my answer to include the dot matrix letters in binary so that others can use the same idea. Commented Jun 10, 2017 at 2:05
• @JustinMariner I popped this onto my profile, hope you don't mind. Nice answer, glad someone completed this challenge :) Commented Jun 10, 2017 at 2:14
• @StephenS Nice, glad you liked it! Commented Jun 10, 2017 at 2:20