Loves me, Loves me not

This simple kids' game is old, but still popular. Since we are living in 21st century now, let's digitize it!

Specification

Program must take no input, unless you are using a language that can't generate random seed - in that case you are allowed to take the seed as an input. Your task is to write a program that will output randomly a total of 3 to 20 lines inclusive: "Loves me..." and "Loves me not..." in turns, as in the game (and one additional line; keep reading).

However, there are some restrictions. Each line should be followed by newline. The first line must be "Loves me...". The last line (either "Loves me" or "Loves me not") should end with exclamation mark or a single dot, respectively. After the last line, you need to output either a heart( <3 ) or a broken heart ( </3 ) in the new line, depending whether "Loves me!" or "Loves me not." was the last sentence.

Trailing whitespace are allowed.

Example Output

Output:

Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me!
<3

Another output:

Loves me...
Loves me not...
Loves me...
Loves me not.
</3

This is the code-golf, so the shortest entry wins!

Also, my first challenge :) Good luck!

• Are there any restrictions on the distribution of the number of lines, i.e., should it be uniformly random, or is it enough that all lengths between 3 and 20 have a positive probability? Sep 15 '15 at 15:13
• I didn't think about this, but I'd say that any distribution is fine - so they don't have to be uniformly random. Sep 15 '15 at 15:14
• Is it 3 to 20 ([3, 20)) or 3 up to including 20 ([3, 20])?
– orlp
Sep 15 '15 at 15:15
• @MatthewRock What if the language we want to use can't seed a random number on their own? Can the user supply a random seed?
– user42643
Sep 15 '15 at 15:35
• @minxomat Whatever, it's just a game. Go on, changed the rules. Sep 15 '15 at 18:25

Pyth, 54535150 48 bytes

pj+*3\.bm+W~!Z"Loves me"" not"+3O18@".!"Z%hZ"</3

• %2tWZ"<</33 for the heart printing saves 1. Not convinced this is the best way though. Sep 15 '15 at 15:32
• @FryAmTheEggman Made it save two.
– orlp
Sep 15 '15 at 15:36
• Merging the last two strings together saves another one, but I had to switch back to my %. Sep 15 '15 at 15:43
• @".!"Z%hZ"</3 saves two bytes Sep 15 '15 at 20:00
• Since there has been no entry for few days, I'm accepting this answer. Congratulations! Sep 24 '15 at 15:02

CJam, 5350 49 bytes

Thanks to Dennis for saving 1 byte.

Imr3+{"Loves me"X!:X" not"*'.3*N}*&"!."X=N'<'/X*3


Test it here.

Explanation

The code just dumps the string in bits and pieces onto the stack, which is printed automatically at the end of the program:

Imr3+         e# Generate a random number in [3,20]
{             e# Execute this block that many times.
"Loves me"  e#   Push "Loves me", we always need that.
X!:X        e#   Toggle X (initially 1) between 0 and 1 and leave it on the stack.
" not"*     e#   Repeat " not" that many times, removing it on every other line.
'.3*N       e#   Push "..." and a newline.
}*
&             e# Set intersection of "..." and newline, turning them into an empty array.
"!."X=        e# Select "!" or "." based on the last value of X.
N'<           e# Push a newline and "<".
'/X*          e# Include "/" or not depending on the last value of X.
3             e# Push a 3.

• one could imagine CJam would've been developed exclusively for code-golf ^^
– ljrk
Sep 15 '15 at 19:55
• @larkey but it is... Sep 15 '15 at 21:14
• @larkey CJam is derived from GolfScript, and GolfScript (as its name implies) is designed for golfing. Sep 16 '15 at 19:16
• @ChrisJester-Young it was ment a bit tongue-in-cheek ;-)
– ljrk
Sep 16 '15 at 21:49

Brainfuck, 2766 bytes (currently invalid)

Just because. I'll add an ungolfed version later.

Code

>+<+[>[>[-]+<-]>[<+>>+[->,----------[<+>[>>>>>>>>>+<<<<<<<<<-]>>>>>>>>>[>+<<<<<<<<<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]]<]<-]>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<[>[-]+<-]>[<+>>>>>>>>>>>>[<<<<<<<<<<+>>>>>>>>>>-]>[<<<<<<<<<<+>>>>>>>>>>-]<<<<<<<<+++++++[<+++++++++++>-]<[<<[>>>>>>>>>>+<<<<<<<+<<<-]>>>[<<<+>>>-]<<[>>>>>>>>>+<<<<<<<+>+<<<-]>>>[<<<+>>>-]<[>>>>>>>>+[<<<<<<<+>+>>>>>>-]<<<<<<[>>>>>>+<<<<<<-]+<[>-<[-]]>[>>>>>+<<<<<-]<<-]<-]++++++[>++++++++<-]>-[<<[>>>>>>>>>+<<<<<<<<+<-]>[<+>-]>-]<<<[-]>[-]+++++[<+++++>-]<[>>>>>>>>>>>+[<<<<<<<<<<+>+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]+<[>-<[-]]>[>>>>>>>>+<<<<<<<<-]<<-]++++++[>>>>>>>>>>+++++++++<<<<<<<<<<-]>>>>>>>>>>[<<+<<<<<<<<+>>>>>>>>>>-]<<<<<<<<<<[>>>>>>>>>>+<<<<<<<<<<-]>>>>>>>[-]>[<+<<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[-]++++++++++++++++++++<<[<<<+>>>-]>>[<<<<<<<<+>+<<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>>[>>[<+<<<+>>>>-]<<<<[>>>>+<<<<-]+>>>[<<->>>-<<<<->>>[-]]<<<[>>[-]+<<-]>>-]>>[>>>-<<<[-]]<<<[-]>>>>>>>>[-]<[>+<<<<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>>>>[-]+++<<<[<<<<<+>>>>>-]>>>[<<<<<<<<<<<+>+<<+>>>>>>>>>>>>-]<<<<<<<<<<<<[>>>>>>>>>>>>+<<<<<<<<<<<<-]>>[>>[<+<<<+>>>>-]<<<<[>>>>+<<<<-]+>>>[<<->>>-<<<<->>>[-]]<<<[>>[-]+<<-]>>-]<[>>>>>>>>-<<<<<<<<[-]]>>>[-]>>>[<<<<<<<+>>>>>>>-]<<<<<<<[>>>>>>>-<<<<<<<[-]]>>>>>>>>>[<<<<<<<<<+>+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-]<[>>>>>>>[-]-<<<<<<<[-]]>>>>>>>[>>>>>>+<<<<<<<<<<<<<<<->>>>>>>>>[-]]<<<<<<<<-]>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<[>[-]+<-]>[<+>>+++++++++++[>+++++++>++++++++++>+++++++++>+++>++++<<<<<-]>-.>+.+++++++.>++.<---.>>-.<<------.>.>>++...[-]<[-]<[-]<[-]<[-]<++++++++++.[-]>>>>>>>[-]>[<+<<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-]>>>>>>>->[-]<[>+<-][-]>[<+<<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[-]<<[<<<<<<+>>>>>>-]->>[<<<<<<<<-<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>[>>>>>>+<<<<<<[-]]<->>>>>>>[<<<<<<<->>>>>>>-]<<<<<<<[>>>>>>>+<<<<<<<-]>>>>>>>[>>>>>>>>+<<<<<<<<<<<<<<<<<->>>>>>>>>[-]]<<<<<<<<-]<[>[-]+<-]>[<+>>++++++[>++++++++++<-]>.---------.[-]<<<-<->>-]>>>>>>>>>>>>>>>>[<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>-]<<<<<<<<<<<<<<<<<[>[-]+<-]>[<+>>+++++++++++[>+++++++>++++++++++>+++++++++>+++>++++<<<<<-]>-.>+.+++++++.>++.<---.>>-.<<------.>.>.<<+.+.+++++.>>>++...[-]<[-]<[-]<[-]<[-]<++++++++++.[-]>>>>>>>[-]>[<+<<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-]>>>>>>>->[-]<[>+<-][-]>[<+<<<<<<<+>>>>>>>>-]<<<<<<<<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[-]<<[<<<<<<+>>>>>>-]->>[<<<<<<<<-<+>>>>>>>>>-]<<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]>[>>>>>>+<<<<<<[-]]<->>>>>>>[<<<<<<<->>>>>>>-]<<<<<<<[>>>>>>>+<<<<<<<-]>>>>>>>[>>>>>>>+<<<<<<<<<<<<<<<<->>>>>>>>>[-]]<<<<<<<<-]<[>[-]+<-]>[<+>>++++++[>++++++++++<-]>.-------------.++++.<<<<->>-]<<]


Pseudocode

loop
get a random byte
until random byte is >2 and <21

point to byte
[
output "Loves me..."
decrease byte by 1
if byte is 0
output "<3"
exit
eif
output "Loves me not..."
decrease byte by 1
]
output "</3"


Sample

When run, the program enters an interactive session waiting for input. Input should be a number. This number is used as a seed.

Seed: 1 (random number is 5, takes 218,168,042 operations)

1
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
<3


Seed: 3 (random number is 20, takes 463,253,048 operations)

3
Loves me...
Loves me not...
(...)
Loves me...
Loves me not...
</3


I'd suggest that you do not seed with 6, as it takes 2,105,900,375 iterations to compute the result :).

Compiling / Running

You need a fast interpreter for this. No online interpreter I've tested could handle the execution speed. The ips (iterations per second) should be more than 100,000,000. So I came up with another solution.

This is a Brainfuck to C compiler written in Brainfuck. You can use any online interpreter to transpile my code to pure C. I suggest using brainfuck.tk. Paste my code in the stdin input, past this code in the code input:

+++[>+++++<-]>>+<[>>++++>++>+++++>+++++>+>>+<++[++<]>---]>++++.>>>.+++++.>------.<--.+++++++++.>+.+.<<<<---.[>]<<.<<<.-------.>++++.<+++++.+.>-----.>+.<++++.>>++.>-----.<<<-----.+++++.-------.<--.<<<.>>>.<<+.>------.-..--.+++.-----<++.<--[>+<-]>>>>>--.--.<++++.>>-.<<<.>>>--.>.<<<<-----.>----.++++++++.----<+.+++++++++>>--.+.++<<<<.[>]<.>>,[>>+++[<+++++++>-]<[<[-[-<]]>>[>]<-]<[<+++++>-[<+++>-[<-->-[<+++>-[<++++[>[->>]<[>>]<<-]>[<+++>-[<--->-[<++++>-[<+++[>[-[-[-[->>]]]]<[>>]<<-]>[<+>-[<->-[<++>-[<[-]>-]]]]]]]]]]]]]<[-[-[>+<-]>]<[<<<<.>+++.+.+++.-------.>---.++.<.>-.++<<<<.[>]>>>>>>>>>]<[[<]>++.--[>]>>>>>>>>]<[<<++..-->>>>>>]<[<<..>>>>>]<[<<..-.+>>>>]<[<<++..---.+>>>]<[<<<.>>.>>>>>]<[<<<<-----.+++++>.----.+++.+>---.<<<-.[>]>]<[<<<<.-----.>++++.<++.+++>----.>---.<<<.-[>]]<[<<<<<----.>>.<<.+++++.>>>+.++>.>>]<.>]>,]<<<<<.<+.>++++.<----.>>---.<<<-.>>>+.>.>.[<]>++.[>]<.>[.---->.---,....]


gcc.exe -c main.c -o main.o
gcc.exe main.o -o loveme.exe


You can also run a copy of the C code online here: via. CodingGround.

Optimizations

There is still some work to do, but the cell re-use is almost optimal.

Remarks

You can use words or phrases as a seed:

Programming Puzzles & Code Golf
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
Loves me not...
Loves me...
<3

• +1 for having the audacity to write a PRNG in Brainfuck ... Sep 15 '15 at 19:36
• @TimmyD There are better ways to write PRNGs in BF, but most of them are time based (run the program, and stop execution at some point, then read memory), but that would require user interaction and two separate programs, which is against the rules.
– user42643
Sep 15 '15 at 19:43
• Nice pseudocode. More people should do that, especially since half the golfing languages are basically unreadable if you don't know them. Sep 16 '15 at 1:54
• Unfortunately your output is wrong. Last "Loves me" should end with an exclamation point(so, "Loves me!"), and "Loves me not" should end with single dot("Loves me not."). Sep 16 '15 at 14:06
• Can we have some pseudocode of the RNG? Sep 19 '15 at 21:27

Javascript (ES6), 11910499 98 bytes

for(i=new Date%18+3,s=i&1?!
<3:.
</3;i--;)s=...
Loves me+(i&1?' not':'')+s

• Good one! It may be shorter to use string concatenation for creating the heart, and possibly in the creation of each line. Mind if I use the new Date trick in my answer? Sep 15 '15 at 18:42
• @ETHproductions Go for it, so long as you're fine with me using those hearts haha (and why didn't I use alert... for some reason I convinced myself arrow functions would be shorter, but needing return negates that...). I actually just got it down to 104 now with some other tricks as well =) Sep 15 '15 at 18:46
• Dang... nice job :) I keep rearranging mine, but always end up at 104. Sep 15 '15 at 18:58
• The breakthrough for me was combining the length/iteration variable by concatenating backwards, and defining the hearts in the initialization. I tried it a while back with little savings, but your heart simplification made it much more efficient. Sep 15 '15 at 19:03
• Wait a minute... Trying this, I get Loves me not... Loves me... Loves me not! <3 and Loves me not... Loves me... Loves me not... Loves me. </3. I think you'll have to change one of the conditionals to fix this. EDIT: Oh, just switch the '' and ' not' in the fourth line. Sep 15 '15 at 19:07

Python, 147

from random import*;t=randint(3,20)
print"\n".join("LLoovveess  mmee  n o t"[i%2::2].strip()+"..."*(i<t-1)for i in range(t))+"!.\n\n<<3/ 3"[t%2::2]


Uses the from random import* instead of import random and randint instead of randrange to save a few bytes. There's probably some bytes left to golf out.

• The alternation "LLoovveess mmee n o t"[i%2::2].strip() seems needlessly complicated. Can't you just do "Loves me"+~i%2*" not"?
– xnor
Sep 16 '15 at 4:17
• Even ["Loves me","Loves me not"][i%2] is more optimal, since you're now wasting chars on .strip() and a couple of spaces. But yes, use xnor's code Sep 18 '15 at 8:36

Javascript (ES6), 110 102 bytes

a='';for(i=j=new Date%18+3;i--;)a+='Loves me'+(j-i&1?'':' not')+(i?...
:j&1?!
<3:.


This was a short but fun little challenge. It may be possible to shorten more. Thanks to Mwr247 for some byte-saving tricks!

Alternate version using repeat(), 105 bytes:

a='';for(i=j=new Date%18+3;i;)a+='Loves me'+' not'.repeat(j-i--&1)+(i?...
:j&1?!
<3:.


Darn JS 5+-char built-in names. Oh well. Suggestions welcome!

• Impressive condensing. I'm curious though, why the 18+3|0? Sep 15 '15 at 18:58
• @Mwr247 Oh, duh, that was from when I used Math.random(). Guess it's not necessary now. Sep 15 '15 at 18:59

Ruby, 91 bytes

(n=3+rand(18)).times{|i|puts"Loves me"+[""," not"][i%2]+(i<n-1?"...":i%2>0?".
</3":"!
<3")}


Common Lisp 106 104 bytes

(format t"~{Loves me~[ not~]~#[~:*~[.~%</~;!~%<~]3~:;...~]~%~}"(subseq'#1=(1 0 . #1#)0(+ 3(random 18))))


This only works on lisps that don't check for a proper sequence (e.g. cmucl, sbcl, clisp) ccl will check for circularity and error out on default safety level. ecl will loop forever.

Explanation:

#1=(1 0 . #1#) generates a circular list containing 1 and 0 and subseq is used to make a list of length [3,20] (this is the only non-portable part, as subseq is only required by the standard to work on proper (i.e. non-circular) lists).

Our format is now operating on a list of 1 0 1 0... of length [3,20]

Explanation of format directives:

~{ iterates over this list

~[ followed by any number of ~; and terminated with ~] will select the Nth item, based on the value of the format argument. This is used here so that the first item in a ~[ will be the "loves me not" case and the second one the "loves me" case. Note that with ~[ a separator of ~:; selects a default case.

~#[ works like ~[ except the argument is the number of remaining arguments. 0 remaining arguments means we are at the end, the default case is to print ...

~:* backs up the argument list one position, which allows us to print the correct trailer.

• This was a group effort by the #lisp IRC channel. Many thanks to phf for the clever iterative format-string and the subseq hack. Sep 16 '15 at 17:28

Perl 5 + -M5.10.0, 76 bytes

print"...
"x!!$_,"Loves me"," not"x$|--for 0..2+rand 18;say$|?"! <3":". </3"  Try it online! Julia, 98 bytes r=rand(3:20) for i=1:r println("Loves me"*(i%2>0?" not":"")*(i<r?"...":i%2>0?".\n</3":"!\n<3"))end  Ungolfed: # Define a random number 3 ≤ r ≤ 20 r = rand(3:20) for i = 1:r # The loveless lines occur when i is even println("Loves me" * (i % 2 > 0 ? " not" : "") * (i < r ? "..." : i % 2 > 0 ? ".\n</3" : "!\n<3")) end  UNIX shell, 193 bytes t=$(seq 2 19|shuf|head -1)
l=t
p=...
while [ $t -ge 0 ];do case$l:$t in t:0)p=!;h=\<3;;f:0)p=.;h=\</3;;esac case$l in t)l=f;n=;; f)l=t;n=\ not;;esac
t=$((t-1)) echo Loves me$n$p done echo$h


Java, 210209203200 177 bytes

• flipped i%2==0 to i%2<1
• trimmed { ... } braces for for-loop, moved e declaration to loop
• re-ordered conditionals
• removed modifiers and unnecessary parentheses, reworked Random usage and increment for i

Note: newline is added below for formatting on this site, the count above is for a single line.

class F{public static void main(String[]a){for(int e=3+(int)(Math.random()*18),i=0;++i<=e;)
System.out.println("Loves me"+(i%2>0?i<e?"...":"!\n<3":" not."+(i<e?"..":"\n</3")));}}


Ungolfed:

class F {
public static void main(String[] a) {
for (int e = 3 + (int) (Math.random() * 18), i = 0; ++i <= e; )
System.out.println("Loves me" + (i % 2 > 0 ? i < e ? "..." : "!\n<3"
: " not." + (i < e ? ".." : "\n</3")));
}
}

• You can save 13 bytes by removing public. Sep 16 '15 at 14:12
• @Luminous I'll still need to keep the one for main() though... Sep 16 '15 at 14:55
• @TimmyD I second that.
– RK.
Sep 16 '15 at 22:39

C, 123, 121, 109 106 characters (108 bytes)

(with a little ♥♥♥cheating♥♥♥)

O;main(o){for(o=time(O)%18+3;o-O++;printf("Loves me%s%s\n",O&1?"":" not",o-O?"...":O%2?"!\n♥":".\n</3"));}


There's also a broken heart Unicode point at 1f494, but I had difficulties finding a font which implements it.

• This shows 120 characters and 122 bytes... Sep 16 '15 at 18:14
• I don't think you need O=0, because C auto-initialize ints to 0? Sep 16 '15 at 18:14
• @FryAmTheEggman Good find! In a previous version I had O in main(o,O) where it had to be initialized.
– Jens
Sep 16 '15 at 18:18
• Nice, I like it! I didn't think of using time as a random number... Clever! Sep 16 '15 at 18:21
• @MatthewRock If you think about it, all the other program using srand(time(0)) will change their answer with the same frequency. The srand is completely useless :-)
– Jens
Sep 16 '15 at 18:22

Python 2, 161159156 144 bytes

from random import*;a=randrange(3,21)
for i in range(a):print'Loves me'+i%2*' not'+('...'if i!=a-1 else'.'if i%2 else'!')
print['<3','</3'][i%2]


It's 39 bytes just to get the random number.

A big thank you to muddyfish, fryamtheeggman, and orlp for their help.

PYG, 109 bytes

a=RR(3,21)
for i in R(a):P('Loves me'+i%2*' not'+('...'if i!=a-1 else'.'if i%2 else'!'))
P(['<3','</3'][i%2])

• You can do the range statement in a single line. you can also do import random as r
– Blue
Sep 15 '15 at 16:07
• you can also put the contents of the last print statement onto the line above.
– Blue
Sep 15 '15 at 16:10
• I think you can change print'</3'if i%2 else'<3' to print['<3','</3'][i%2] to save 3 bytes.
Sep 15 '15 at 16:20
• Yes indeed I can; thanks! Sep 15 '15 at 16:22
• Thanks! Interestingly, import random as r;a=r.randrange(3,21) and import random;a=random.randrange(3,21) are the same length. Sep 15 '15 at 16:24

PowerShell, 121119 111 Bytes

$i=2..19|Random;1..$i|%{"Loves me$(if(!($_%2)){" not"})..."};"Loves me$(if(!($i%2)){"!n<"}else{" not.n</"})3"


Edit--actually shorter to explicitly include "Loves me" rather than declaring $l Edit2--forgot that I can golf for() loops by pipelining...durr... Not too shabby. Uses inline code execution blocks $(...) to dynamically adjust the printed string as we're for()-looping. Note that because this uses an implicit Get- in front of Random to save a couple bytes, this may operate extremely slowly on certain PowerShell versions. Reference

Expanded below for clarification:

# Create a collection of (2,3,4,...18,19) and pipe it as input to Get-Random
$i = 2..19 | Get-Random # Create a collection of (1,2,...$i-1,$i) and pipe it to seed a ForEach-Object loop 1..$i | ForEach-Object {
if(!($_%2)) { # If the input number is even, we're on an even line Write-Output "Loves me not..." } Else { # The input number is odd Write-Output "Loves me..." } } If(!($i%2)) {
# Our random number is odd
Write-Output "Loves me!"
Write-Output "<3"
}
Else {
# Our random number is even
Write-Output "Loves me not."
Write-Output "</3"
}


C++, 210193184 168 bytes

In C++.. because.. Why not? :)

#include <iostream>
main(){auto&c=std::cout;srand(time(0));int i,j=3+rand()%18;while(i++<j)c<<"Loves me"<<(i%2?"":" not")<<(i==j?"":"...\n");c<<(j%2?"!\n<3":".\n</3");}


Live: 210 193 184 168

Just hope that any of my changes are not platform dependent.

Thanks to Ben Voigt for the help. Also, thanks to all the comments, they were very helpful.

• Humn.. just realize its 3 to 20. I will fix that later. Probably will add 2 more bytes... j=3+(int)(rand()*17.0/RAND_MAX) Sep 15 '15 at 19:33
• You can save a lot by replacing #define c cout and using namespace std; by auto&c=std::cout; Sep 15 '15 at 22:55
• Also save some with int i=0,j=rand()*20.0/RAND_MAX;while(i<j) Sep 15 '15 at 23:00
• Hello, found a bug: Last line should be "Loves me!", not "Loves me." Sep 16 '15 at 10:55
• I'd say it's okay - C and C++ are similar. And right now this code is longer than Java... Sep 16 '15 at 15:01

Groovy, 110 bytes

A groovy kind of love:

int r=Math.random()*18;print((0..r+2).collect{"Loves me"+" not"*(it%2)}.join('...\n')+['!\n<3','.\n</3'][r%2])


Python 2, 117 bytes

from random import*
n=randint(3,20)
print"...\n".join("Loves me"+i%2*" not"for i in range(n))+[".\n</3","!\n<3"][n%2]


Observe that every Loves me( not)? is followed by ... and a newline, except for the last one. So this looks like a job for join.

• A bit late but ".!\n\n<</33"[n%2::2] is 2 bytes shorter. Sep 17 '15 at 20:18
• @FryAmTheEggman Yeah, I did see that but decided not to steal it from Loovjo. In the meantime, someone else has posted exactly that solution. [shrug] Sep 17 '15 at 22:16
• I hadn't noticed someone else posting it, but I am pretty sure my comment was the first that had it in it, so you can use it if you want :P Sep 17 '15 at 22:27

R, 141132128114111 109 bytes

Code

k=sample(3:23,1);for(i in 1:k)cat("Loves",c("me not...\n","me...\n","me not.\n</3","me!\n<3")[1+i%%2+2*!i<k])


Ungolfed

k <- sample(3:23, 1)        # Generates random "k" number from 3 to 23
for(i in 1:k) {             # Loop this block increasing i from 1 until k by 1
cat                       # Concatenate and paste everything inside this block
("Loves",                 # Push "Loves" on every iterations of the loop
c(                    # Create a vector of strings
"me not...\n",      # Push string to the index "1" of vector
"me...\n",          #   to the index "2"
"me not.\n</3",     #   to the index "3"
"me!\n<3"           #   to the index "4"
)[1+i%%2            # Subset the vector by the index (1 or 2)
+2*!i<k])}        #   if final iteration of loop then index += 2 (3 or 4)


I've took some inspiration from Eric Brooks code.

Edit 1: Now the code correctly outputs the last punctuation as pointed out by Martin
Edit 2: Changed the for loop to a sapply and included the hearts inside the last line string.
Edit 3: Removed the {} and changed +(x==k)*2 to +2*!x<k
Edit 4: Back to for loop and removed the () from (i%%2)+1
Edit 5: Wrote me 4 times and removed the sep=""

R, 119111 105 bytes

x<-sample(3:20,1);cat(rep(c("Loves me...\n","Loves me not...\n"),x)[1:x]);cat(ifelse(x%%2==1,"<3","</3"))


Edits 1,2: Coding the two options explicitly is saving space.

• You can save a byte by using = for assignment rather than <- and another by doing x%%2>0 in place of x%%2==1. Also note that this doesn't handle the last line correctly; there should be a . or ! rather than .... (See example output in the question.) Sep 15 '15 at 20:43
• @Alex A. You don't need x%%2>0 either; just x%%2 Sep 15 '15 at 22:29
• Good points, thanks. I need to go back and fix the ending Sep 16 '15 at 14:50

C 226 bytes

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main(){srand(time(NULL));int i=rand()%18+3;int j;for(j=0;j<i;j++)printf("Loves me%s%s\n",(j%2)?" not":"",(j==i-1)?(j%2)?".":"!":"...");printf("<%s3\n",(j%2)?"":"/");}


(With formatting)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
srand(time(NULL));
int i = rand()%18 + 3;
int j;
for (j = 0; j < i; j++)
printf("Loves me%s%s\n", (j % 2) ? " not" : "", (j==i-1) ? (j % 2) ? "." : "!" : "...");
printf("<%s3\n", (j%2) ? "" : "/");
return 0;
}

• Remove return type from main (-5 bytes), make i and j global with default type (-8 bytes, -3 more because of default 0 in j), use 0 instead of NULL (-3). Other things - use only one variable and make the loop counting down maybe. Import stdio is not usually needed when golfing. Sep 16 '15 at 10:15

Python 2, 115 bytes

from random import*
n=randint(2,20)
print'...\n'.join('Loves me'+i%2*' not'for i in range(n))+'.!\n\n<</33'[n%2::2]


PHP, 191187146 165 Bytes

$x=rand(5,22);for($i=2;++$i<=$x;){echo"\nLoves me";if($i%2<1)echo" not";if($i<$x)echo"...";if($i==$x&&$i%2<1){echo".\n</3\n";}elseif($i==$x&&$i%2>0){echo"!\n<3\n";}}  Ungolfed: $x=rand(5,22);
for($i=2;++$i<=$x;){ echo "\nLoves me"; if($i%2<1) echo " not";
if($i<$x) echo "...";
if($i==$x && $i%2<1){ echo ".\n</3\n"; } elseif($i==$x &&$i%2>0){
echo "!\n<3\n";
}
}


48,49 bytes for pyth and cjam ... wow :)

• Changed $i%2==0 to$i%2<1 (x2) and $i%2!=0 to$i%2>0 (x2) Sep 16 '15 at 21:48
• turns out ternary operators are not the best answer at all times :) Sep 16 '15 at 22:02

mSL, 178176156 154 bytes

Edit 1: Changed == 0 to < 1
Edit 2: Removed unnecessary whitespace, thanks AlexA!
Edit 3: Removed parentheses

alias l {
var %n 1
while %n <= $rand(3,20) { var %m$+(Love me,$iif($calc(%n % 2) < 1,$chr(32)$+ not),...)
echo %m
inc %n
}
echo $iif(n isin %m,</3,<3) }  • Your solution is currently 176 bytes, not 177. Is all of the whitespace necessary? If not, you could shorten your code by a significant amount simply by removing unneeded whitespace. Sep 16 '15 at 18:12 • @AlexA. Oh don't know why I wrote 177, and thanks for pointing out the necessity of whitespace, it is indeed not needed! Sep 16 '15 at 22:45 Perl, 97 bytes $_='She loves me...
'x(3+rand 18);s/(me.*?)me/$1me not/gs;s/e...$/e!
<3/;s/t...
$/t. <\/3/;print  Readable version: $_="She loves me...\n"x(3+rand 18);
s/(me.*?)me/$1me not/gs; s/e...$/e!\n<3/;
s/t...\$/t.\n<\/3/;
print


Hassium, 265 Bytes

func main(){rnd=new Random();times=rnd.next(3,21);println("Loves me...");for(x=0;x<times-1;x++){if(x%2==0)println("Loves me not...");else println("Loves me...");}if((times-1)%2==0){println("Loves me not.");println("</3");}else{println("Loves me!");println("<3");}}


• Your solution is currently 458 bytes, not 523. You can better your score by removing unnecessary whitespace and shortening variable names. See the other Hassium solution for examples. Sep 16 '15 at 18:16
• As I noted on the other Hassium answer, the random number generator seems to be extremely biased. I ran this 500 times with the latest version and only got two </3. Sep 16 '15 at 20:05
• +Dennis The Random generator is built directly on top of the C# Random number generator. See: github.com/HassiumTeam/Hassium/blob/master/src/Hassium/… Sep 16 '15 at 21:19
• It doesn't seem to get seeded correctly. If I execute rnd = new Random();rnd.next(0,2); 1000 times, the distribution is OK. However, if I execute rnd = new Random(); once and rnd.next(0,2); 1000 times, I always get exactly 533 0s and 467 1s. Sep 16 '15 at 21:53

C# (160)

The code is inspired by the answer from h.j.k., credit goes to him.

class P{static void Main(){for(int e=3+new Random().Next(0,18),i=0;++i<=e;)Console.WriteLine("Loves me"+(i%2>0?i<e?"...":"!\n<3":" not."+(i<e?"..":"\n</3")));}}


Ungolfed:

class P
{
private static void Main()
{
for (int e = 3 + new Random().Next(0, 18), i = 0; ++i <= e;)
Console.WriteLine("Loves me" + (i % 2 > 0 ? i < e ? "..." : "!\n<3" : " not." + (i < e ? ".." : "\n</3")));
}
}


Hassium, 161 165 bytes

This answer is non-competing, since it requires a version of the interpreter that is newer than this challenge.

func main()println(range(-1,t=new Random().next(3,21)).select(x=>"Loves me"+(x%2==0?" not":"")+(x==t-2?(x%2==0?".":"!"):"...")).join("\n"),"\n",t%2==0?"</3":"<3");


Unleashing the power of Hassium.

Ungolfed version

func main()
{
t = new Random().next(3,21); # initialize the love number
loveNumber = range(-1, t); # creates an array like this Array { -1 0 1 2 ... ... up to n } where n is a random number between 3 and 21 }
loves = loveNumber.select(x => # iterates through the array
{
ret = "Loves me";
if (x % 2 == 0) # check if x is even
{
ret += " not"; # add ' not' to the result
}
ret += (x == t ? (x % 2 == 0 ? "." : "!") : "...");
return ret;
}).join("\n"); # join the result with Unix newlines (\n)
println(loves); # print it
println(t%2==0?"</3":"<3");
}

• On this site we typically only allow languages and features created prior to the posting of the challenge. In this case, it appears you added the range function to Hassium after the challenge was posted. Sep 16 '15 at 18:31
• Alex A., the range has always been in Hassium, I just forgot to put in the correct file so it wasn't usable. Sep 16 '15 at 18:40
• 1. If this particular code did not work with the interpreter that was available at the time this challenge was posted, your answer is technically invalid and should contain a disclaimer stating that it's non-competing. 2. The random number generator seems to be extremely biased. I ran this 500 times and only got two </3. Sep 16 '15 at 19:51
• @Dennis however, if you got various lengths, I would say it's fine - I specified that any distribution is allowed - so although 2 in 500 isn't much, it's still acceptable, by the rules. Sep 17 '15 at 9:39

Lua, 137 132 bytes

Probably can be golfed a lot more, but here it is for now:

t=math.random(3,20)for i=1,t do io.write(i%2==0 and"Loves me"or"Loves me not")print(i==t and(i%2==0 and"!\n<3"or".\n</3")or"...")end


Code explanation and ungolfed:

t=math.random(3,20) --Generates a random number between 1 and 30. We need to assign it to a variable to check if the loop is over later.
for i=1,t do
io.write(i%2==0 and"Loves me"or"Loves me not") --If i%2 is 0 write without a newline Loves me, if not print Loves me not.
print(i==t and (i%2==0 and"!\n<3" or ".\n</3") or "...") --If it is not the end of the loop, put ..., else if we ended on an even print ! a newline, and then a heart, but if we ended on an odd put ., a newline and a broken heart :(
end


Edit: Chopped off some whitespace.

Jelly, 55 bytes (non-competing?)

“¢zḞzƘFq»,;¥“ not”ṁ18X+2¤j“...¶”µċ⁷Ḃ©”/ẋ;3⁾¶<;®ị⁾.!¤;⁸;


Try it online!

As usual Jelly sucks with strings.