i love yOu i lOve you i love yOu!
Jelly, 41 40 35 33 bytes
Thanks to @Dennis for making the end ṖṖCG
! (complement C
= 1-x
in place of logical not ¬
)
“ƝƓỊ⁹Ȥ⁶Ị⁺‘ẋ8_“¤ÐŒ#'/‘¦32BFs21ṖṖCG
TryItOnline
How?
“ƝƓỊ⁹Ȥ⁶Ị⁺‘ẋ8_“¤ÐŒ#'/‘¦32BFs21ṖṖCG - Main link: no arguments
“ƝƓỊ⁹Ȥ⁶Ị⁺‘ - code page indexes [150,147,176,137,154,134,176,138]
(bitwise negated values of ordinals of "ilOveyOu")
ẋ8 - repeat eight times
_ - subtract
¦ - apply to indexes
“¤ÐŒ#'/‘ - code page indexes [3,15,19,35,39,47]
(the indexes of the lowercase Os)
32 - literal 32 (subtracting 32 from the bitwise negated
'O's makes them bitwise negated 'o's)
B - binary (all are 8 bits, hence the negation)
F - flatten list
s21 - split into slices of length 21
ṖṖ - pop (remove the last two slices)
C - complement (transform the bits to what they should be)
G - format as a grid
(inserts both the spaces and line feeds)
"Colour" version, 77 bytes
“¤Ɓ¥J¬ ¥ƲėNėR½5ðḃḍCṬ’b19‘“Y^‘jĖŒṙḂ
“ƝƓỊ⁹Ȥ⁶Ị⁺‘ẋ8_“¤ÐŒ#'/‘¦32BFż¢Ḅị“¹0°1”s21ṖṖG
TryItOnline
Jelly has no colour output, but this is much easier for me to see anyway (I am colour blind)...
° ¹ ¹ ° ¹ ° ° ¹ ° ¹ ¹ ° ¹ ¹ ° ° ° ¹ ¹ ° ¹
¹ ¹ ¹ ° ¹ ¹ ¹ ° ¹ ¹ ° ° ¹ ¹ ° ° ¹ ° ¹ ° ¹
¹ ¹ ¹ ° ° ¹ ° ¹ ° ° ¹ ¹ ¹ ¹ ° ¹ ¹ ¹ ° ¹ °
¹ ° ¹ ¹ ° ¹ ° ° ¹ ° ¹ ¹ ° ¹ ¹ ° ° ° ¹ ° °
¹ ¹ ¹ ¹ ° 1 1 1 ° ¹ ¹ ° ° 1 1 0 ° ¹ ° ¹ °
¹ ¹ ¹ 1 0 0 1 0 1 1 ° 1 1 1 1 0 1 1 ¹ ° ¹
° ¹ ° 1 1 0 1 0 0 1 ° 1 1 0 1 1 0 0 ° ¹ ¹
° ¹ ¹ 1 1 0 1 1 1 0 1 1 0 0 1 1 0 0 1 ° ¹
° ¹ 1 1 1 0 0 1 0 1 0 0 1 1 1 1 0 1 1 ¹ °
¹ ° 1 0 1 1 0 1 0 0 1 0 1 1 0 1 1 0 0 ° ¹
° ° ¹ 1 1 1 0 1 1 1 0 1 1 0 0 1 1 0 0 ¹ °
¹ ° ¹ 1 1 1 0 0 1 0 1 0 0 1 1 1 1 0 ¹ ¹ ¹
° ¹ ° ¹ 0 1 1 0 1 0 0 1 0 1 1 0 ¹ ¹ ° ° °
¹ ¹ ° ¹ ¹ 1 1 0 1 1 1 0 1 1 0 0 ¹ ¹ ° ° ¹
° ¹ ° ¹ ¹ ¹ 1 0 0 1 0 1 1 0 1 ¹ ¹ ¹ ° ¹ ¹
¹ ° ¹ ° ¹ ° ¹ 1 0 1 0 0 1 0 ¹ ¹ ° ¹ ¹ ° °
° ¹ ° ° ¹ ¹ ¹ ¹ 0 1 1 1 0 ¹ ¹ ° ° ¹ ¹ ° °
¹ ° ¹ ° ¹ ¹ ¹ ¹ ° 0 1 0 ¹ ¹ ° ¹ ¹ ¹ ¹ ° ¹
¹ ¹ ° ¹ ° ¹ ° ¹ ¹ ° 1 ° ° ¹ ° ¹ ¹ ° ¹ ¹ °
° ° ¹ ° ° ¹ ¹ ¹ ¹ ° ¹ ¹ ¹ ° ¹ ¹ ° ° ¹ ¹ °
° ¹ ° ¹ ° ¹ ¹ ¹ ¹ ° ° ¹ ° ¹ ° ° ¹ ¹ ¹ ¹ °
¹ ¹ ¹ ° ¹ ° ¹ ° ¹ ¹ ° ¹ ° ° ¹ ° ¹ ¹ ° ¹ ¹
° ° ° ¹ ° ° ¹ ¹ ¹ ¹ ° ¹ ¹ ¹ ° ¹ ¹ ° ° ¹ ¹
How?
“¤Ɓ¥J¬ ¥ƲėNėR½5ðḃḍCṬ’b19‘“Y^‘jĖŒṙḂ - Link 1: no arguments
“¤Ɓ¥J¬ ¥ƲėNėR½5ðḃḍCṬ’ - base 250 of a big number
b19 - convert to base 19, yields a list of integers
‘ - increment those numbers
“Y^‘ - get code page indexes [89,94]
j - join: [89,3,5,3,8, ... ,3,19,1,94]
- {left-right, top-bottom} runs of colours
Ė - enumerate [[1,89],[2,3],[3,5],[4,3],[5,8], ...]
Œṙ - run-length decode [89 1s, 3 2s, 5 3s, 3 4s, 8 5s, ...]
Ḃ - mod 2
“ƝƓỊ⁹Ȥ⁶Ị⁺‘ẋ8_“¤ÐŒ#'/‘¦32BFż¢Ḅị“¹0°1”s21ṖṖG - Main link: no arguments
“ƝƓỊ⁹Ȥ⁶Ị⁺‘ẋ8_“¤ÐŒ#'/‘¦32BF - same as the original to get 1s and 0s
ż - zip with
¢ - last link (1) as a nilad
Ḅ - binary to integer (vectorises)
ị - index into
“¹0°1” - string "¹0°1"
s21 - split into length 21 slices
ṖṖ - pop last two unused slices
G - format as a grid
Actually, 58 bytes
73*8╙:13542├`≈"÷≥"E`M"«%s₧ªn%s6û"7*%"♠n≥6û"+¿├`' +`M╪♂Σ♂Ri
Try it online!
Explanation
There are three main parts here, so I'm going to break it down accordingly.
Part 1: Constructing the base-256 string
We're actually going to construct the binary string reversed, to take advantage of Actually's stack-based (LIFO) structure and to avoid complications with leading zeros in the binary string. Thus, the target binary string is 110011011101111001000110110100101101010111011110010100111101010011001101110111100100011011010010110101011101111011010011110101001100110111011110010001101101001011010101110111101101001111010100110011011101111011000110110100101101010111011110010100111101010011001101110111100100011011010010110101011101111001010011110101001100110111011110110001101101001011010101110111101101001111010100110011011101111001000110110100101101010111011110010100111101010011001101110111101100011011010010110
, which is equivalent to 20083405242288679348048842451418880256193335738939042905519679590571514414673488599852759703515507690399267425671627412178904636115120346432419478
in decimal. In base-256 (using the CP437 character table for conversion), the corresponding string is ♠n≥6û«≥₧ªn≥6û«÷₧ªn≥6û«÷₧ªn÷6û«≥₧ªn≥6û«≥₧ªn÷6û«÷₧ªn≥6û«≥₧ªn÷6û
. To construct the original binary string, we construct the base-256 string (taking advantage of the pattern in it), and perform base conversions to decimal and binary.
The base-256 string has the following format (spaces and newlines added for clarity):
♠n≥6û
« (either ≥ or ÷) ₧ªn (either ≥ or ÷) 6û
(7 times)
Thus, each of the 7 middle sections can be formed by using the scaffold «%s₧ªn%s6û
and replacing the %s
parts with either ≥
or ÷
.
The specific sequence of ≥
s and ÷
s we need is ≥≥÷≥÷÷≥≥≥÷÷≥≥÷
. Since we need this as a list of length-1 strings, the naïve way of representing this would be "≥≥÷≥÷÷≥≥≥÷÷≥≥÷"#
(push the string, make it into a list). However, we can do slightly better. By interpreting that string as a binary number (where ≥
represents 1
and ÷
represents 0
), we get 13542
in decimal. By converting this back to binary (using the traditional 1
s and 0
s), and indexing into a length-2 string, we can get the list using one less byte than the naïve method.
:13542├`≈"÷≥"E`M"«%s₧ªn%s6û"7*%"♠n≥6û"+
:13542├ push 13542, convert to binary
`≈"÷≥"E`M for each bit:
≈ convert to integer (from string)
"÷≥"E index into "÷≥"
"«%s₧ªn%s6û"7* push the scaffold for the middle section
% old-style Python string formatting to fill in the scaffold
"♠n≥6û"+ prepend the beginning piece
Part 2: Converting to binary
This part is much more straightforward. If Actually had the capability to directly convert base-256 to binary, we'd use that. Unfortunately, it doesn't, so we'll have to use decimal as an intermediary format.
The ,
in the following code represents the code from Part 1 - for explanatory purposes, I've replaced the Part 1 code with ,
to read the output from Part 1 from STDIN. It is not part of the actual final code.
8╙,¿├
, Part 1 result
8╙ ¿ convert from base-256 to decimal
├ convert to binary
Part 3: Formatting
If the challenge was to merely output the binary string as-is, we'd be done. However, we still have some formatting to do to get the binary string into a 21 x 23 rectangle.
As in Part 2, the ,
represents the output from the previous part, and is not part of the actual code.
73*,`' +`M╪♂Σ♂Ri
, output from Part 2
`' o`M insert a space after every character
73* ╪ chunk into 21 pieces
♂Σ concatenate each piece
♂R reverse each piece
i flatten
(implicitly print)
For those keeping track at home, this is the equivalent Python 3 code (481 bytes):
print('\n'.join([''.join(' '+c for c in bin(sum('\x00☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\xa0'.index(c)*256**i for i,c in enumerate(("♠n≥6û"+("«%s₧ªn%s6û"*7)%tuple("÷≥"[int(b)]for b in bin(13542)[2:]))[::-1])))[2:])[i*42:-~i*42][::-1]for i in range(23)][::-1]))
JavaScript (ES6), 169 ... 136 135 bytes
let f =
_=>"0213021203131214".replace(x=/./g,v=>0+[a=1768714102,a-8192,a-=66265089,a+8192,3][v].toString(2)).replace(x,(c,i)=>`
`[+!(i%21)]+c)
console.log(f());
Saved 2 bytes thanks to Andrakis
Saved 4 bytes thanks to Hedi
Saved 3 5 bytes thanks to Neil
Colored version, 249 bytes (237 bytes of JS + 12 bytes of CSS)
The JS code outputs the ASCII art with bold tags for the heart. 12 bytes of CSS are required to colorize in red. (Is that byte count fair?)
let f =
_=>"0213021203131214".replace(x=/./g,v=>0+[a=1768714102,a-8192,a-=66265089,a+8192,3][v].toString(2)).replace(x,(c,i)=>`
`[+!(y=i/21|0,x=i%21)]+([57568,a=261112,a,b=524280,b+4,b+4,b,a+1024,65520][y-4]&1<<x|y>12&x>y-9&x<29-y?c.bold():c))
document.getElementById("o").innerHTML = f();
b{color:red}
<pre id="o"></pre>