106
votes
\$\begingroup\$

As a little joke in the office someone wanted a script that randomly picks a name, and said person will make a round of drinks.

Let's call the people John, Jeff, Emma, Steve and Julie.

I thought it would be funny to make a script that seems random at a quick glance, but actually always gives the same person as the output (Up to you who you choose).

Highest voted answer wins after a week

And the winner is....

Paul R with (currently) 158 votes.

The answers here are great, and if anyone else has any other ideas what haven't been posted yet, please add them, I love reading through them.

\$\endgroup\$
10
  • 44
    \$\begingroup\$ xkcd.com/221 \$\endgroup\$
    – AstroCB
    Jun 16, 2014 at 19:30
  • 6
    \$\begingroup\$ @AstroCB one of my favourites. Right behind bobby tables. \$\endgroup\$
    – Cruncher
    Jun 16, 2014 at 20:08
  • 50
    \$\begingroup\$ It seems like it would be sneakier if it was random, except for never picking one person. \$\endgroup\$ Jun 16, 2014 at 22:52
  • 6
    \$\begingroup\$ @AstroCB this one is also fantastic: dilbert.com/strips/comic/2001-10-25 \$\endgroup\$ Jun 18, 2014 at 10:08
  • 3
    \$\begingroup\$ I went through the first page: most answers always choose John, 2nd highest is Julie, Jeff is chosen rarely and Steve by 1. Even Ray got chosen by one but nobody chose Emma. Moral of the story: when standing in a line to decide randomly who will buy the drinks, name yourself Emma. \$\endgroup\$ Jul 15, 2014 at 19:33

65 Answers 65

171
votes
\$\begingroup\$

C

It's important to decide who is buying as quickly as possible, so as not to waste precious drinking time - hence C is the obvious choice in order to get maximum performance:

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

int main(void)
{
    const char *buyer;
    int n;

    srand(time(NULL)); // make sure we get a good random seed to make things fair !
    n = rand();
    switch (n % 5)
    {
        case 0: buyer = "John";
        case 1: buyer = "Jeff";
        case 2: buyer = "Emma";
        case 3: buyer = "Steve";
        case 4: buyer = "Julie";
    }
    printf("The person who is buying the drinks today is: %s !!!\n", buyer);
    return 0;
}

Explanation:

This would work just fine if there was a break; after each case in the switch statement. As it stands however each case "falls through" to the next one, so poor Julie always ends up buying the drinks.

\$\endgroup\$
7
  • 17
    \$\begingroup\$ +1 for performance -- much faster than rolling a physical die! ;) \$\endgroup\$
    – Jwosty
    Jun 17, 2014 at 3:46
  • 16
    \$\begingroup\$ I'm thinking about optimising it further, perhaps with SIMD or GPGPU, just to get a little more performance. ;-) \$\endgroup\$
    – Paul R
    Jun 17, 2014 at 7:12
  • 7
    \$\begingroup\$ Absolutely real live applicable. No one would ever even question that it was an accident in the slightest. \$\endgroup\$
    – iFreilicht
    Jun 18, 2014 at 14:04
  • 5
    \$\begingroup\$ Is it just me or is this one too obvious to spot? \$\endgroup\$
    – Alvin Wong
    Jun 23, 2014 at 11:09
  • 3
    \$\begingroup\$ @AlvinWong I didn't notice it immediately. Then again, I don't use C regularily, or any other language that descended from BCPL. \$\endgroup\$
    – Rhymoid
    Jun 23, 2014 at 12:52
164
votes
\$\begingroup\$

PHP

Couldn't let this go, so here is another one:

$f = fopen('/dev/random','r');
$s = fread($f, 4);
fclose($f);

$names = ['John', 'Jeff', 'Emma', 'Steve', 'Julie'];

echo $names[$s % count($names)];

This is actually not guaranteed to produce john, but chances are very good. PHP will happily take whatever /dev/random have to offer see that it (probably) can't parse it and come up with the very reasonable number 0 instead. After all, alerting the programmer to a potential error is considered a deadly sin in PHP.

\$\endgroup\$
3
  • 25
    \$\begingroup\$ You got to love PHP - and even better, it will sometimes rarely choose someone else. So if you're lucky it will just seem a little biased at first \$\endgroup\$
    – Falco
    Jun 16, 2014 at 16:18
  • 142
    \$\begingroup\$ +1000 for "...alerting the programmer to a potential error is considered a deadly sin in PHP." \$\endgroup\$
    – jsedano
    Jun 16, 2014 at 16:51
  • \$\begingroup\$ obligatory phpsadness \$\endgroup\$
    – clapp
    Nov 2, 2015 at 15:58
85
votes
\$\begingroup\$

Haskell

It's too transparent if it always returns the same name so try the following

import Control.Monad
import System.Exit
import Control.Concurrent
import Control.Concurrent.MVar


data Person = John | Jeff | Emma | Steve | Julie deriving (Show, Enum)

next Julie = John
next p = succ p

rotate :: MVar Person -> IO ()
rotate mp = modifyMVar_ mp (return . next) >> rotate mp

main :: IO ()
main = do
    mp <- newMVar John
    forkIO $ rotate mp
    putStrLn "Shuffling"
    readMVar mp >>= print
    exitWith ExitSuccess

Whenever you want it to be random:

[~]$ runghc prog.hs
Shuffling
Steve

[~]$ runghc prog.hs
Shuffling
Julie

And for your unfortunate target:

[~]$ runhugs prog.hs
Shuffling
John

[~]$ runhugs prog.hs
Shuffling
John

Hugs only implements cooperative multitasking, so the rotate thread will never run

\$\endgroup\$
4
  • 24
    \$\begingroup\$ That's diabolical! \$\endgroup\$
    – Daenyth
    Jun 16, 2014 at 17:59
  • 8
    \$\begingroup\$ Feels like photographing a dice which has not yet stopped moving. \$\endgroup\$
    – Vi.
    Jun 19, 2014 at 8:25
  • 1
    \$\begingroup\$ @Vi. That is a nice analogy. Luckily the use of MVars guarantee that the picture will not be blurry. :) \$\endgroup\$
    – monocell
    Jun 19, 2014 at 8:41
  • \$\begingroup\$ @monocell Well, technically, even a photo of a moving object can be clear. \$\endgroup\$ Jan 27, 2016 at 14:59
73
votes
\$\begingroup\$

Bash - maximum simplicity

A very simple example - let's avoid any problems by doing it the textbook way. Don't forget to seed the generator from the system clock for a good result!

#!/bin/bash

names=(John Jeff Emma Steve Julie)   # Create an array with the list of names
RANDOM=$SECONDS                      # Seed the random generator with seconds since epoch
number=$((RANDOM % 5))               # Pick a number from 0 to 4
echo ${names[number]}                # Pick a name

This relies on the user not knowing what the $SECONDS builtin actually does; it returns the number of seconds since the current shell started. As it's in a script, the shell always started zero seconds ago, so the generator is always seeded with 0 and Julie always buys the beer.

Bonus:

This one stands up to scrutiny quite well; If you enter the same code on the commandline instead of in a script, it will give random results, because $SECONDS will return the length of time the user's interactive shell has been running.

\$\endgroup\$
3
  • 9
    \$\begingroup\$ \o/ Mean!!! Really mean!!! $SECONDS ftw! \o/ \$\endgroup\$
    – user19214
    Jun 17, 2014 at 17:47
  • \$\begingroup\$ What happens if you source this, instead of just executing it? Will the shebang still trigger a new shell or something? \$\endgroup\$
    – jpmc26
    Jun 26, 2014 at 14:22
  • 1
    \$\begingroup\$ @jpmc26: if you execute it with source then it's exactly the same as if you'd typed the commands on the commandline yourself; #!/bin/bash is a comment so it's ignored. This is true of any script. \$\endgroup\$
    – Riot
    Jun 26, 2014 at 21:57
57
votes
\$\begingroup\$

C#

using System;
using System.Linq;

namespace PCCG {
    class PCCG31836 {
        public static void Main() {
            var names = new string[]{ "John", "Jeff", "Emma", "Steve", "Julie" };
            var rng = new Random();
            names.OrderBy(name => rng.Next());
            Console.WriteLine(names[0]);
        }
    }
}

This might not fool people who are familiar with the .Net API, but people who don't know it might believe that OrderBy modifies the object you call it on, and it's a plausible error for a newbie to the API to make.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Even if OrderBy hypothetically modified the object, would that call actually sort the list randomly? As someone unfamiliar with .NET, my first guess was that since rng.Next() is only called once, the array would be sorted by a constant, resulting in no change (or a change that depends only on the sorting algorithm). \$\endgroup\$
    – Brilliand
    Jun 24, 2014 at 21:05
  • 1
    \$\begingroup\$ @Brilliand The argument passed to OrderBy isn't a static value, it's executed every time an element is sorted, and in this case returns random values without comparing any values. It would actually work correctly if the line was names = names.OrderBy(name => rng.Next()); \$\endgroup\$ Jun 25, 2014 at 0:12
  • 1
    \$\begingroup\$ The => indicates that this is a C# lambda expression (closure). \$\endgroup\$
    – Snowbody
    Jun 25, 2014 at 17:38
44
votes
\$\begingroup\$

PowerShell

$names = @{0='John'; 1='Jeff'; 2='Emma'; 3='Steve'; 4='Julie'}
$id = random -maximum $names.Length
$names[$id]

This will always output John.

$names is a System.Collections.Hashtable which doesn't have a Length property. Starting with PowerShell v3, Length (and also Count) can be used as a property on any object. If an object does not have the property, it will return 1 when the object is not null, else it will return 0. So in my answer, $names.Length evaluates as 1, and random -maximum 1 always returns 0 since the maximum is exclusive.

\$\endgroup\$
0
42
votes
\$\begingroup\$

Q

show rand `John`Jeff`Emma`Steve`Julie;
exit 0;

Q always initialises its random number seed with the same value.

\$\endgroup\$
5
  • 8
    \$\begingroup\$ so basically it's not random at all \$\endgroup\$ Jun 16, 2014 at 14:39
  • 3
    \$\begingroup\$ @SamCreamer The purpose of the question is very much to make the output non-random. But this does look random so it definitely fits the bill \$\endgroup\$
    – Cruncher
    Jun 17, 2014 at 13:54
  • 4
    \$\begingroup\$ Sorry, I meant Q's random numbers aren't that random, this question does certainly meet the criteria. Didn't mean to come across that way! \$\endgroup\$ Jun 17, 2014 at 15:31
  • \$\begingroup\$ Yeah, so you have to find your own way to generate a random seed every time you want to use rand? Sounds... useful. \$\endgroup\$
    – DLeh
    Jun 19, 2014 at 16:20
  • 1
    \$\begingroup\$ Can set the random seed manually very easily...start the interpreter with the -S 1234 option or do \S 1234 from the interpreter \$\endgroup\$
    – skeevey
    Jun 19, 2014 at 18:02
34
votes
\$\begingroup\$

Perl

use strict;

my @people = qw/John Jeff Emma Steve Julie/;
my @index = int(rand() * 5);

print "Person @index is buying: $people[@index]\n";

Prints: Person X is buying: Jeff (where X is from 0-4)

Abusing scalar context a bit. @index = int(rand() * 5) places a random integer from 0 - 4 in the 0th position of the @index list. When printing the array, it properly prints the random integer in @index, but when using as an array index in $people[@index], @index uses scalar context, giving it the value of the list size, i.e. 1.

Interestingly enough, @people[@index] makes it index properly.

Interestingly enough @people[@index] is a hash slice in Perl, so @index is evaluated in the list context; in this case, it's a single entry list and that's why it works correctly

\$\endgroup\$
6
  • \$\begingroup\$ So in C(++) terms, there is an implicit conversion from list to scalar happening because when indexing, a scalar is expected? \$\endgroup\$
    – iFreilicht
    Jun 18, 2014 at 14:15
  • \$\begingroup\$ @iFreilicht Correct. In Perl, expressions can be evaluated as a list or as a scalar, depending on where they appear. As a result, the same expression might mean different things, depending on context. A list variable (i.e. a variable with the @ prefix), in "list context," is interpreted as all its elements, but in "scalar context," is a scalar equal to the total number of elements in the list. Hence, inside the string, the list variable has list context and gets interpolated, and we get Person X is buying. But as an array index, it gets scalar context, and gets interpreted as 1. \$\endgroup\$
    – Allen G
    Jun 18, 2014 at 15:29
  • 3
    \$\begingroup\$ Problem with this is that when a Perl programmer sees my @index = ..., he immediately wonders "WTF?!". \$\endgroup\$
    – derobert
    Jun 19, 2014 at 19:16
  • \$\begingroup\$ @derobert, Why would you wonder? You see code like that quite often... my @letters = 'a' .. 'z'; my @squares = map $_**2, 1..20; my @sorted = sort { lc $a cmp lc $b } @words; etc. \$\endgroup\$
    – Matthias
    Jun 26, 2014 at 14:44
  • \$\begingroup\$ @Matthias because the line is to pick and store a single value, and instead of a scalar it's being stored in an array. \$\endgroup\$
    – derobert
    Jun 26, 2014 at 15:02
23
votes
\$\begingroup\$

ECMAScript

// Randomly pick a person on only one line!
var people = [('John', 'Jeff', 'Emma', 'Steve', 'Julie')];

console.log(people[new Date() % people.length | 0]);

It always picks Julie.

It has brackets inside the square brackets, and the comma operator returns the value of its right operand.
It's also very easy to miss. I've missed it before in real code.

\$\endgroup\$
3
  • \$\begingroup\$ This is delightful. Finally, a use for that terrible, terrible operator. \$\endgroup\$
    – Keen
    Jun 17, 2014 at 16:31
  • 5
    \$\begingroup\$ The comma in that context is technically an operator, rather than a separator. ecma-international.org/ecma-262/5.1/#sec-11.14 And it is terrible. Unless you want your code to be hard to read. As you do here. So, kudos. \$\endgroup\$
    – Keen
    Jun 17, 2014 at 20:18
  • 2
    \$\begingroup\$ @Cory Yes, I agree - although I use it all the time for Code Golf with function expressions (e.g. (a,b)=>(a=b[0],b)). I've clarified my answer. \$\endgroup\$
    – Toothbrush
    Jun 17, 2014 at 22:28
20
votes
\$\begingroup\$

C#

using System;

namespace LetsTroll {
    class Program {
        static void Main() {
            var names = new string[]{ "John", "Jeff", "Emma", "Steve", "Julie" };
            var random = new Random(5).NextDouble();
            var id = (int)Math.Floor(random);
            Console.WriteLine(names[id]);
        }
    }
}

The trick is, the method new Random().NextDouble() returns a double between 0 and 1. By applying Math.Floor() on this value, it will always be 0.

\$\endgroup\$
7
  • 24
    \$\begingroup\$ It didn't withstand my quick glance. ;) \$\endgroup\$ Jun 16, 2014 at 12:42
  • 1
    \$\begingroup\$ @TimS. like that? :P \$\endgroup\$
    – Knerd
    Jun 16, 2014 at 14:17
  • 2
    \$\begingroup\$ +1, Much better - I know what you're really doing, but it could fool someone not too familiar with the API. \$\endgroup\$
    – Tim S.
    Jun 16, 2014 at 14:20
  • 1
    \$\begingroup\$ I don't know about this. If you are going to specify a seed, why not just use the proper way of getting a "random" int: var random = new Random(5); var id = random.NextInt(5); \$\endgroup\$
    – clcto
    Jun 16, 2014 at 15:08
  • 2
    \$\begingroup\$ @clcto In my opinion, including it twice is more likely to make someone do a double take, ask why, and see the problem. Including it once, and then including unnecessary code afterward, gives a bit of redirection/underhandedness. Bonus: if someone fixes one of the bugs, another exists. \$\endgroup\$
    – Tim S.
    Jun 16, 2014 at 15:30
18
votes
\$\begingroup\$

C#

var names = new string[] {"John", "Jeff", "Emma", "Steve", "Julie"};
var guidBasedSeed = BitConverter.ToInt32(new Guid().ToByteArray(), 0);
var prng = new Random(guidBasedSeed);
var rn = (int)prng.Next(0, names.Length);
Console.WriteLine(names[rn]);

Hint:

Generate seed from GUID. Guids have 4 × 10−10 chance of collision. Super random.

Answer:

At least when you use Guid.NewGuid(), whoops! (Sneaky way to make seed always 0). Also pointless (int) for misdirection.

\$\endgroup\$
3
  • \$\begingroup\$ The other way I might do it, is to get AddRange muddled with Concat when adding names to a List<string>. Did occur to me to have a Hashset with a sneaky IEqualityComparer, but it would be just far too unusual. In my credit there weren't many (if any) seed based answers when I posted this. \$\endgroup\$
    – Nathan
    Jun 16, 2014 at 14:08
  • \$\begingroup\$ I'll guess you had the same idea as I did, but you were a bit faster and made it a bit harder to see. +1! \$\endgroup\$
    – tsavinho
    Jun 16, 2014 at 14:47
  • 7
    \$\begingroup\$ Seeding the random number generator is an obvious trick, but you've hidden it brilliantly here. Lovely work. \$\endgroup\$
    – TRiG
    Jun 16, 2014 at 23:50
18
votes
\$\begingroup\$

bash / coreutils

This is taken almost verbatim from a script I wrote for a similar purpose.

#!/bin/bash
# Sort names in random order and print the first
printf '%s\n' John Jeff Emma Steve Julie | sort -r | head -1

Even forgetting to use an upper case R is a mistake I have occasionally made in real life scripts.

\$\endgroup\$
3
  • 3
    \$\begingroup\$ could you give a better explanation? Your current one is really short and not helpful to someone who isn't really familiar with bash. \$\endgroup\$
    – iFreilicht
    Jun 18, 2014 at 14:16
  • 6
    \$\begingroup\$ -r specifies reverse (lexicographic) sort, so Steve will always be picked. It could be seen as an innocent typo of -R for random sort \$\endgroup\$
    – Max
    Jun 18, 2014 at 16:15
  • 3
    \$\begingroup\$ That's a good reminder not to trust comments, but to carefully read the code! \$\endgroup\$
    – TecBrat
    Jun 20, 2014 at 17:34
16
votes
\$\begingroup\$

Ruby

names = ["John", "Jeff", "Emma", "Steve", "Julie"]

puts names.sort{|x| rand()}.first

This would work correctly with sort_by, but sort expects a comparison function that works like <=>. rand()'s result will always be positive, so it will always produce equivalent results provided your Ruby implementation's sort algorithm is deterministic. My Ruby 1.9.3 always outputs Julie.

\$\endgroup\$
12
votes
\$\begingroup\$

Ruby

names = ["John", "Jeff", "Emma", "Steve", "Julie"]

puts names[rand() % 5]

rand() with no arguments produces a random float between 0 and 1. So modulo 5 does nothing, and when slicing into an array with a float argument Ruby just rounds it down, so this always returns John.

\$\endgroup\$
11
votes
\$\begingroup\$

Perl

three srands will make it three times more random!

#!perl
use feature 'say';

sub random_person {
    my ($aref_people) = @_;
    srand; srand; srand;
    return $aref_people->[$RANDOM % scalar @$aref_people];
}

my @people = qw/John Jeff Emma Steve Julie/;
my $person = random_person(\@people);

say "$person makes next round of drinks!";

explanation

there is no $RANDOM in perl, it's an undefined variable. the code will always return the first element from the list - drinks on John :)

edit:

after going through the code, one of the five guys has decided to fix the obvious error, producing the following program:

#!perl
use feature 'say';

sub random_person {
    my ($aref_people) = @_;
    return $aref_people->[rand $#$aref_people];
}

my @people = qw/John Jeff Emma Steve Julie/;
my $person = random_person(\@people);

say "$person buys next round of drinks!";

can you tell who did it just by looking at the code?

explanation:

in Perl, $#array returns the index of last element; since arrays are zero-based, given a reference to an array with five elements, $#$aref_people will be 4.
rand returns a random number greater or equal to zero and less than its parameter, so it will never return 4, which effectively means Julie will never buy drinks :)

\$\endgroup\$
1
  • 1
    \$\begingroup\$ $RANDOM is a real feature in bash, ksh and zsh (but not in perl). \$\endgroup\$
    – kernigh
    Jun 16, 2014 at 19:21
10
votes
\$\begingroup\$

Python

Everybody knows that you can't trust randomness in such a small sample space; to make it truly random, I've abandoned the outdated method of picking a name from a list, and instead my program will spell out a completely random name. Since most of the names in the office had 4 letters, we'll settle for that.

import random

def CHR (n):
    # Just easily convert a number between 0 and 25 into a corresponding letter
    return chr(n+ord('A'))

# Seed the RNG with a large prime number. And multiply it by 2 for good measure.
random.seed (86117*2)

# Now, let's see what COMPLETELY RANDOM name will be spelled out!
totallyRandomName = ''
for i in range(4) :
    totallyRandomName += CHR(int(random.random()*26))
    
print (totallyRandomName)

Naturally, I did some preparation work to make sure I pick the right seed.

\$\endgroup\$
2
  • 15
    \$\begingroup\$ Seeding the random number generate with a constant is just too obvious.. \$\endgroup\$ Jun 16, 2014 at 22:59
  • \$\begingroup\$ @BrendanLong It would definitely raise eyebrows. People would want to test it to make sure its random. And when it's not, guess who's buying drinks. \$\endgroup\$
    – jfa
    Jun 25, 2014 at 17:39
10
votes
\$\begingroup\$

C

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

int main(void)
{
char *name[]={"John", "Jeff", "Emma", "Steeve", "Julie"};

int i;
int n=rand()%10000;
int r=3;

for (i=0; i<10000+n; i++) // random number of iteration
    {
    r=(r*r)%10000; // my own PRNG (square and mod)
    }

printf("%s", name[r%5] );
}

Sorry, Jeff!

After a few iteration r==1 mod 5, because of math. Morality : don't write your own PRNG if you're bad at math. :)

\$\endgroup\$
10
votes
\$\begingroup\$

C++x11

#include <vector>
#include <iostream>

int main () {
  std::srand(time(NULL));
  std::vector<std::string> choice{("jen","moss","roy")};
  std::cout << choice[rand()%choice.size()] << std::endl;
}

Size of vector is actually 1 due to the parenthesis used in the initializer list. Comma operator will discard all the names and return the last one, hence the buyer is always Roy.

\$\endgroup\$
10
votes
\$\begingroup\$

Scala

I know my users will be skeptical, so I have included a proof that my randomness is truly fair!

object DrinkChooser {
  
  def main(args: Array[String]): Unit = {
    proveRandomness()
    val names = List("John","Jeff","Emma","Steve","Julie")
    val buyer = names(randomChoice(names.size))
    println(s"$buyer will buy the drinks this time!")
  }
  
  def proveRandomness(): Unit = {
    val trials = 10000
    val n = 4
    val choices = for (_ <- 1 to 10000) yield randomChoice(n)
    (choices groupBy(identity)).toList.sortBy(_._1) foreach { case (a, x) =>
      println(a + " chosen " + (x.size * 100.0 / trials) + "%")
    }
  }
  
  def randomChoice(n: Int): Int = {
    var x = 1
    for (i <- 1 to 1000) { // don't trust random, add in more randomness!
      x = (x * randomInt(1, n)) % (n + 1)
    }
    x
  }
  
  // random int between min and max inclusive
  def randomInt(min: Int, max: Int) = {
    new scala.util.Random().nextInt(max - min + 1) + min
  }

}

One example run:

1 chosen 25.31%
2 chosen 24.46%
3 chosen 24.83%
4 chosen 25.4%
John will buy the drinks this time!

Unless someone else gets extremely lucky, John will always buy the drinks.

The "proof" of randomness relies on the fact that rand(1, 4) * rand(1, 4) % 5 is still evenly distributed between 1 and 4, inclusive. But rand(1, 5) * rand(1, 5) % 6 is degenerate. There's the possibility you get a 0, which would then make the final result 0 regardless of the rest of the "randomness".

\$\endgroup\$
10
votes
\$\begingroup\$

Javascript (with Underscore.js)

Since javascript does not have a built in shuffle we'll be using Underscore.js

var people = ['John', 'Jeff', 'Emma', 'Steve', 'Julie'];
_.shuffle(people); // Shuffle the people array
console.log("Next round is on", people[0]);

_.shuffle returns the shuffled array, it does not modify in place as Array.prototype.sort(), sorry John

\$\endgroup\$
9
votes
\$\begingroup\$

JavaScript

Second try, this one's a little trickier:

var getRandomEntry = function(args){
    return args[Math.floor(Math.random() * arguments.length)]; 
}

alert(getRandomEntry(["peter","julie","samantha","eddie","mark"]));

The arguments variable is locally accessible for functions and is an array of all arguments passed in to the function. By using simple naming and passing in an array to the function itself, you can spoof that we're not taking the length of the array, but in fact the length of the arguments list (which is 1). This can be even better executed by using special chars or a font type.

\$\endgroup\$
1
  • \$\begingroup\$ This wasn't the hardest to spot. Anyone who has constructed an arbitrary N-ary function in JavaScript knows about the arguments variable. \$\endgroup\$ Oct 23, 2015 at 4:00
8
votes
\$\begingroup\$

C++

To be fair we should run many, many trials and pick whomever is selected the most often.

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

static const char *names[] = { "John", "Jeff", "Emma", "Steve", "Julie" };

int main() {
    srand(time(NULL));
    std::map<int, int> counts;

    // run 2^31 trials to ensure we eliminate any biases in rand()
    for (int i = 0; i < (1<<31); i++) {
        counts[rand() % (sizeof(names)/sizeof(*names))]++;
    }

    // pick the winner by whomever has the most random votes
    int winner = 0;
    for (std::map<int, int>::const_iterator iter = counts.begin(); iter != counts.end(); ++iter) {
        if (iter->second > counts[winner]) {
            winner = iter->first;
        }
    }

    printf("%s\n", names[winner % (sizeof(names)/sizeof(*names))]);
}

What's the value of 1<<31? Sorry, John.

\$\endgroup\$
5
  • \$\begingroup\$ The answer to your spoiler question is UB. I am undecided if that makes is better or worse. \$\endgroup\$
    – nwp
    Jun 22, 2014 at 17:57
  • \$\begingroup\$ @nwp Well, sure, but it holds anywhere that int is 32-bit 2's complement, which seems to be the case even on 64-bit (with gcc). I haven't tested on Clang, though. \$\endgroup\$
    – fluffy
    Jun 22, 2014 at 20:16
  • \$\begingroup\$ No it doesn't hold anywhere where an int is 32-but 2's complement. The value of 1 << 31 is undefined. You are lucky though, undefined behavior makes the compiler chose whatever it feels like and since it is made for speed it will just decide to do nothing, which happens to be what you want. \$\endgroup\$
    – nwp
    Jun 22, 2014 at 20:24
  • \$\begingroup\$ @nwp 1<<31 == 0x80000000 no matter what, by the very definition of <<, and on 32-bit 2's complement, that's INT_MIN. Are you maybe thinking about 1<<32 which may or may not == 0? (Because on x86, 1<<32 usually evaluates to 1...) \$\endgroup\$
    – fluffy
    Jun 23, 2014 at 18:18
  • \$\begingroup\$ @nwp It's actually implementation-defined. Now if we were talking about C, then it would be undefined. \$\endgroup\$ Jun 25, 2014 at 18:01
7
votes
\$\begingroup\$

T-SQL (2008+)

SELECT TOP 1 name
FROM
 (VALUES('John'),('Jeff'),('Emma'),('Steve'),('Julie')) tbl(name)
ORDER BY RAND()

Explanation:

In MS SQL Server, RAND() only evaluates once per execution. Every name always gets assigned the same number, leaving the original ordering. John is first. Sucks for John.

Suggested improvement:

T-SQL can produce decent quality, per-row random numbers with RAND(CHECKSUM(NEWID())).

\$\endgroup\$
1
  • \$\begingroup\$ I think ORDER BY NEWID() will suffice (no need to CHECKSUM) \$\endgroup\$
    – Jacob
    Jun 17, 2014 at 4:41
7
votes
\$\begingroup\$

Lua

buyer={'John', 'Jeff', 'Emma', 'Steve', 'Julie'}
   -- use clock to set random seed
math.randomseed(os.clock())
   -- pick a random number between 1 and 5
i=math.random(5)
io.write("Today's buyer is ",buyer[i],".\n")

os.clock() is for timing purposes, os.time() is what ought to be used with math.randomseed for good RNG. Sadly, Julie always buys (at least on my computer).

\$\endgroup\$
2
  • \$\begingroup\$ math.random() with no arguments also returns a number in the range [0,1). -1 for not catching that. \$\endgroup\$
    – mniip
    Jun 16, 2014 at 17:04
  • \$\begingroup\$ @mniip: Truly deserved too! I've fixed it now. \$\endgroup\$
    – Kyle Kanos
    Jun 16, 2014 at 17:37
6
votes
\$\begingroup\$

Idiomatic C++11

When drinks are involved, it's especially important to be up to date with the latest standards and coding styles; this is a great example of a highly efficient and idiom-compliant C++11 name picker.

It is seeded from the system clock, and outputs the seed along with the name for verification each time.

#include <vector>
#include <chrono>
#include <random>
#include <iostream>

auto main()->int {
  std::vector<std::string> names;           // storage for the names
  names.reserve(5);                         // always reserve ahead, for top performance
  names.emplace_back("John");               // emplace instead of push to avoid copies
  names.emplace_back("Jeff");
  names.emplace_back("Emma");
  names.emplace_back("Steve");
  names.emplace_back("Julie");

  std::mt19937_64 engine;                   // make sure we use a high quality RNG engine
  auto seed((engine, std::chrono::system_clock::now().time_since_epoch().count()));  // seed from clock
  std::uniform_int_distribution<unsigned> dist(0, names.size() - 1);     // distribute linearly
  auto number(dist(engine));                // pick a number corresponding to a name
  std::string name(names.at(number));       // look up the name by number
  std::cout << "Seed: " << seed << ", name: " << name << std::endl;  // output the name & seed
  return EXIT_SUCCESS;                      // don't forget to exit politely
}

Try this live: http://ideone.com/KOet5H

Ok so this actually is pretty good code overall; there are a lot of red herrings to make you look too closely at the code to notice the obvious - that the RNG is never actually seeded :) In this case seed is just an integer, and while it looks like engine is passed as a parameter to a seeding function, it's actually just ignored. The seed variable really is set from the clock, so it can be output at the end along with the name to add insult to injury, but it'll still always be Steve who buys the drinks.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ It kills me that it doesn't use an initializer list for the names. At the very least, you've definitely succeeded in providing code that just feels over- engineered. I can't tell whether it's because of the "compliance" or all of the noise comments :P \$\endgroup\$
    – vmrob
    Jun 22, 2014 at 17:03
6
votes
\$\begingroup\$

JavaScript

console.log(["Jeff", "Emma", "Steve", "Julie"][Math.floor(Math.random(5))]);

Well, sorry, Math.random doesn't take a parameter, and will always return a number from [0, 1). Still, it is a happy variadic function and doesn't complain about arguments!

\$\endgroup\$
5
votes
\$\begingroup\$

Python

names=["John", "Jeff", "Emma", "Steve", "Julie"]
import random # Import random module
random.seed(str(random)) # Choose strictly random seed
print(random.choice(names)) # Print random choice

str(random) gives a constant string; not a random value

\$\endgroup\$
1
  • 6
    \$\begingroup\$ A somewhat-irrelevant note: if you're using Python 3.2 or later, the second argument to random.seed() must be 2 (the default). If you pass version=1, the hash() of the string will be used as a seed instead of the entire string, and because Python randomly seeds strings' hash values starting in 3.2, you'll get an actually-random name. \$\endgroup\$ Jun 16, 2014 at 22:56
5
votes
\$\begingroup\$

Perl

Emma had better not forget her purse! Runs under strict and warnings.

use strict;
use warnings;

# Use a hash to store names since they're more extendible

my %people;
$people{$_}++ for qw/John Jeff Emma Steve Julie/;

print +(@_=%people)[rand@_];  # 'cos (keys %people)[rand( keys %people )]
                              # is just too long-winded.

Explanation here.

\$\endgroup\$
1
  • \$\begingroup\$ Perl 5.18 changed this a bit, by introducing hash key randomization (to avoid hash collision complexity attacks). \$\endgroup\$
    – 0..
    Jan 2, 2015 at 9:47
4
votes
\$\begingroup\$

JavaScript

function getDrinksBuyer(){ 
    var people = ["Jeff", "Emma", "Steve", "Julie"];
    var rand = Math.random(0,4)|0;
    return people[rand];
}

The |0 results in 0 all the time but looks like it's doing some other rounding.

\$\endgroup\$
4
  • \$\begingroup\$ I like it. Though I would do parseInt(Math.random(0, 4)) and maybe add comments like - Math.random returns a double, so convert it to an integer first \$\endgroup\$
    – Claudiu
    Jun 16, 2014 at 15:39
  • 5
    \$\begingroup\$ The trick is actually that Math.random cares nothing for our meager parameters. It chooses numbers its own way. the |0 is correctly rounding the unexpected result, and so is not a source of any trickery. \$\endgroup\$
    – Keen
    Jun 17, 2014 at 16:35
  • \$\begingroup\$ |0 is very obvious to some (all of us most likely), but I would bet there's a lot who have no idea what it does. That's the group I was relying on tricking. \$\endgroup\$
    – Matt
    Jun 18, 2014 at 5:04
  • 3
    \$\begingroup\$ @Matt I mean that |0, if you know what it does, looks like it's rounding down, and it is rounding down, so it's not a deception. (And if someone has no idea what |0 does, then there's no use for deceptive code; you can just tell them whatever you want them to believe.) Instead, the unexpected behavior in your answer is based on the fact that Math.random(0,4) is functionally identical to Math.random(), because Math.random doesn't use parameters. \$\endgroup\$
    – Keen
    Jun 19, 2014 at 19:18
4
votes
\$\begingroup\$

J

;(?.5) { 'John'; 'Jeff'; 'Emma'; 'Steve'; 'Julie'

Poor Julie... Trivia: this might've been the cleanest J I've ever written...

This code is actually correct, except for one thing. ?. is the uniform rng: ?.5 will always return 4. ?5 would've been correct.

\$\endgroup\$
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.