22
\$\begingroup\$

Have you ever wanted to ask the compiler "Why?" Most of us have been frustrated when the code isn't working as it should. Mathworks has therefore implemented a nice little function, why, that answers the question. To give a few examples from MATLAB:

why
The programmer suggested it.

why
To fool the tall good and smart system manager.    

why(2)
You insisted on it.

why(46)
Bill insisted on it.

Your task is to implement the why function in your language. The function should work with and without an input argument (alternatively use input 0 or -1). The function must be named why (or, writing why(n) in STDIN should result in the appropriate string being printed).

If no argument is given, or the argument is zero or negative, the output string should be a random, valid phrase. So, there should be a function why, why(), why(0) or why(-1) that returns a random sentence.

If an input argument, n is given (function argument, not STDIN), the output should be the n'th string (defined below). So, why(1) should always output (print/display) the same result.

The sentences are built up as follows (Type 1, Type 2 and Special). All sentences end with !.

"Person" "ending" !
"Verb" "adjective" "Person" !
A list of special cases

The list of persons:

Stewie
Peter
Homer
The programmer
The system manager
You

The list of endings:

suggested it
insisted on it
did it

The list of verbs are:

To fool
To satisfy
To please

The list of adjectives:

the smart
the bald
the tall
the rich
the stupid

The list of special cases:

How should I know?
Stop asking!
Don't ask!

The way to select a numbered one is:

Type of sentences:

Odd number => Type 1
Even number => Type 2
n % 7 = 0 => Type 3 (% is the modulus operator)

Names: The nth name is defined using modulus (%).

n = 1:   1 % 7  => Stewie
n = 2:   2 % 7  => Peter
...
n = 6:   6 % 7  => You
n = 7:   7 % 7  => How should I know?
n = 11:  11 % 7 => The programmer
n = 14:  14 % 7 => Stop asking!
n = 21:  21 % 7 => Don't ask!

Endings: The nth ending is also defined using the modulus. Assume the endings (1, 2 and 3) are listed like (1 2 2 3). As the numbers are always odd, use ((n+1)/2 % 4)

n = 1:    ((1+1)/2 % 4)  => suggested it
n = 3:    ((3+1)/2 % 4)  => insisted on it
n = 13:   ((13+1)/2 % 4) => did it

Adjectives: The nth adjective is defined using the modulus. As the numbers are always even, use: (n % 10)/2

n = 2:   (2 % 10)/2 => Smart
n = 6:   (6 % 10)/2 => The tall
...

Verbs: The nth verb is also defined using the modulus. Assume the verbs (1, 2 and 3) are listed like (1 2 2 3) As the numbers are always even for verbs, use (n % 8) / 2

n = 2:   (2 % 8)/2 => To fool
n = 4:   (4 % 8)/2 => To satisfy
n = 6:   (6 % 8)/2 => To satisfy
n = 8:   (8 % 8)/2 => To please

Now, the way to create a random one should be fairly simple, simply select a random n.

Some examples:

why
You suggested it!

why
To fool the tall Homer!

why
Don't ask!

why(1)
Stewie suggested it!

why(14)
Stop asking!

why(8)
To please the rich Stewie!

Standard code golf rules apply. A winner will be selected one week from the day the challenge was posted.

\$\endgroup\$
11
  • \$\begingroup\$ writing why in the stdin should return the string I might be able to work with that. Does it have to be lowercase why or would WHY be acceptable? \$\endgroup\$
    – Dennis
    Oct 7, 2015 at 16:00
  • \$\begingroup\$ Lower and upper case are both fine. \$\endgroup\$ Oct 7, 2015 at 16:28
  • \$\begingroup\$ Also the Endings should not need /2 to work. That gives fractional values. 13 should also be insisted (14/2=7 %4 = 3 = 2nd of insisted). \$\endgroup\$ Oct 7, 2015 at 16:44
  • 3
    \$\begingroup\$ Does it matter if you end up with cases like the rich The programmer due to the specified the? \$\endgroup\$ Oct 7, 2015 at 17:03
  • 1
    \$\begingroup\$ @StewieGriffin The words The and To in your lists should probably be lowercase to match your examples... \$\endgroup\$
    – mbomb007
    Oct 7, 2015 at 17:06

9 Answers 9

5
\$\begingroup\$

JavaScript (ES6) 345

Not sure about the numbers, but here is my attempt.

Test running the snippet below in an EcmaScript compliant browser.

why=n=>(n<1?n=Math.random()*840|0:0,s="suggested,insisted on,did,fool,satisfy,please,stupid,smart,bald,tall,rich,Don't ask!,How should I know?,Stop asking!,Stewie,Peter,Homer,programmer,system manager,You".split`,`,n%7?(p=s[n%7+13],n&1?(p>'a'?'The ':'')+p+` ${s['2011'[-~n/2%4]]} it!`:`To ${s['5344'[n%8/2]]} the ${s[n/2%5+6]} ${p}!`):s[11+n%3])  

for(o='',i=0;++i<1e3;)o+=i+':'+why(i)+'\n';O.innerHTML=o

function test() { R.innerHTML=why(+I.value) }

// Less golfed

WHY=n=>(
  n=n<1?Math.random()*999|0:n,
  s=["suggested", "insisted on", "did", "fool", "satisfy", "please",
     "stupid", "smart", "bald", "tall", "rich",
     "Don't ask!", "How should I know?", "Stop asking!",
     "Stewie", "Peter", "Homer", "programmer", "system manager", "You"],
  n%7
    ? ( p=s[n%7+13],
        n&1
        ? (p>'a'?'The ':'')+p+` ${s['2011'[-~n/2%4]]} it!`
        : `To ${s['5344'[n%8/2]]} the ${s[n/2%5+6]} ${p}!`)
    : s[11+n%3]
)  
#O { height:300px; width:50%; overflow:auto }
#I { width:2em }
Why(<input id=I>)<button onclick=test()>-></button><span id=R></span>
<pre id=O>

\$\endgroup\$
3
  • \$\begingroup\$ Nice answer! Can't speak authoritatively on the number validity, but you can save 1 byte (!) using 0 as your string delimiter instead of ,! \$\endgroup\$ Oct 8, 2015 at 7:26
  • 1
    \$\begingroup\$ @DomHastings I think that trick is no more needed with template strings. split(0) is the same length of split',' (pretend these are backticks) \$\endgroup\$
    – edc65
    Oct 8, 2015 at 7:34
  • \$\begingroup\$ Ahhh, sorry, I was thinking you could lose the brackets, this isn't coffeescript! :) \$\endgroup\$ Oct 8, 2015 at 7:35
3
\$\begingroup\$

C#, 502 bytes

This project needs to have the AssemblyName set to why which will produce an executable with the correct name.

Fully golfed:

using System;class W{static void Main(string[]i)int n=i.Length>0?int.Parse(i[0]):new Random().Next();string[]s={"Don't ask!","How should I know?","Stop asking!"},v={"To please ","To fool ","To satisfy ",null},a={"the stupid","the smart","the bald","the tall","the rich"},p={"","Stewie","Peter","Homer","The programmer","The system manager","You"},e={"suggested it!","insisted on it!",null,"did it!"};Console.Write(n%7<1?s[n%3]:n%2<1?(v[n%8/2]??v[2])+a[n%10/2]+" {0}!":"{0} "+(e[n/2%4]??e[1]),p[n%7]);}}

Indentation and new lines for clarity:

using System;
class W{
    static void Main(string[]i)
        int n=i.Length>0
            ?int.Parse(i[0])
            :new Random().Next();
        string[]
            s={"Don't ask!","How should I know?","Stop asking!"},
            v={"To please ","To fool ","To satisfy ",null},
            a={"the stupid","the smart","the bald","the tall","the rich"},
            p={"","Stewie","Peter","Homer","The programmer","The system manager","You"},
            e={"suggested it!","insisted on it!",null,"did it!"};
        Console.Write(
            n%7<1
                ?s[n%3]
                :n%2<1
                    ?(v[n%8/2]??v[2])+a[n%10/2]+" {0}!"
                    :"{0} "+(e[n/2%4]??e[1]),
            p[n%7]
        );
    }
}

Example input/output:

>Why
To fool the bald Homer!
>Why 1
Stewie suggested it!
\$\endgroup\$
2
\$\begingroup\$

Powershell 437 461 453 Bytes

Edit: Missed the duplicated verbs

Splitting between the corpus and the calculations for byte-count

  • 267 Bytes = Pre-coded text (excluding to,the,it and ! since they have fixed places).
  • 186 Bytes = calculation

Sets default argument to 0 if not specified. If argument is <1 then it gets a random number <99 fn:1 and reruns. Technically this means -50 will work as well, being treated as a random case.

function why{param($b=0)$p=@('Stewie','Peter','Homer','The programmer','The system manager','You');$e=@('did','suggested','insisted on','insisted on');$v=@('please','fool','satisfy','satisfy');$a=@('stupid','smart','bald','tall','rich');$s=@("Don't ask!",'How should I know?','Stop asking!');if($b-le0){why(Get-Random 99)}elseif(!($b%7)){$s[$b/7%3]}else{$n=$p[$b%7-1];if($b%2){"$n $($e[($b+1)/2%4]) it!"}else{"To $($v[$b%8/2]) the $($a[$b%10/2]) $n!"}}}

Explanation:

# Any -1 in calculations is to account for arrays starting at index 0
# Final key placed in position 0 for indexing (4%4 = 0)
# Powershell 1 = True, 0 = False
if($b-le0){why(Get-Random 99)}          # If not positive, choose random number
elseif(!($b%7))                         # $b%7 means special so use that
  {$s[$b/7%3]}                          # Divide by 7 and find modulo, use that phrase.
else{$n=$p[$b%7-1]                      # Get the correct person (Used in both types). 6 max
if($b%2){"$n $($e[($b+1)/2%4]) it!"}    # Create type 1 sentence
else{"To $($v[$b%8/2]) the $($a[$b%10/2]) $n!"} # Type 2

fn:1 99 Chosen to save a byte. If there are more than 99 possible sentences above (did not calculate) increase to 999 or 9999 as applicable (+1/2 bytes)

\$\endgroup\$
2
\$\begingroup\$

MUMPS, 379 bytes

f(s,i) s:'i i=$L(s,"^") q $P(s,"^",i)
why(n) s:'n n=$R(840) s p="Stewie^Peter^Homer^The programmer^The system manager^You",e="suggested^insisted on^did",v="fool^satisfy^please",a="smart^bald^tall^rich^stupid",s="How should I know?^Stop asking!^Don't ask!" q:n#7=0 $$f(s,n#3) q:n#2 $$f(p,n#7)_" "_$$f(e,n+1/2#4)_" it!" q "To "_$$f(v,n#8/2)_" the "_$$f(a,n#10/2)_" "_$$f(p,n#7)_"!"

When no input is given, a random number in 0..839 is generated.

Usage:

>w $$why(15)
Stewie did it!
>w $$why()
Don't ask!

MUMPS's left-to-right evaluation strategy saves a good few bytes on parentheses here.

Side note: see those strings that look like "foo^bar^baz^qux"? Those are so-called "delimited strings", and are the standard way of storing lists that fit within the maximum string size limit, since MUMPS does not actually have lists/arrays (or, indeed, any data structures besides trees). For lists too large to fit in a single string, we instead use trees of depth 1 and put the values on the leaves of the tree. Fun!

\$\endgroup\$
1
  • \$\begingroup\$ +1: MUMPS, of all languages, really needs a why function. ;) \$\endgroup\$
    – DLosc
    Oct 14, 2015 at 0:47
1
\$\begingroup\$

Emacs Lisp 473 Bytes

(defun why(n)(if(and n(> n 0))(let*((p'(t"Stewie""Peter""Homer""The programmer""The system manager""You"))(e'("did""suggested""insisted on""insisted on"))(v'("please""fool""satisfy""satisfy"))(a'("stupid""smart""bald""tall""rich"))(s'("Don't ask!""How should I know?""Stop asking!"))(q(nth(% n 7)p)))(cond((=(% n 7)0)(nth(%(/ n 7)3)s))((=(% n 2)1)(format"%s %s it!"q(nth(%(/(1+ n)2)4)e)))(t(format"To %s the %s %s!"(nth(/(% n 8)2)v)(nth(/(% n 10)2)a)q))))(why(random 99))))

Largest 'waste' is probably the format,%s... sections. If variables could be inlined into the strings without the specification it would save 10 bytes on %s and another 12 on format

\$\endgroup\$
1
\$\begingroup\$

Ruby 396 378 372 bytes

I'm sure this is not golfed to the max.

p=%w[a Stewie Peter Homer The\ programmer The\ system\ manager You]
why=->n{n<1 ? why[rand(99)+1]:n%7<1 ? $><<%w[a How\ should\ I\ know? Stop\ asking! Don't\ ask!][n/7]:n%2<1 ? $><<'To '+%w[fool satisfy satisfy please][n%8/2-1]+' the '+%w[smart bald tall rich stupid][n%10/2-1]+' '+p[n%7]+?!:$><<p[n%7]+' '+%w[a suggested insisted\ on insisted\ on did][(n+1)/2%4]+' it!'}

Edit: I've just realized that I don't know operator precedence. Oh well..

\$\endgroup\$
4
  • \$\begingroup\$ rand(21) seems way too small \$\endgroup\$
    – edc65
    Oct 7, 2015 at 20:02
  • \$\begingroup\$ What about 99? :P \$\endgroup\$ Oct 7, 2015 at 20:04
  • \$\begingroup\$ There are 108 compound sentences + 3 special cases. The sequence of sentences is periodic but the period ... I don't know \$\endgroup\$
    – edc65
    Oct 7, 2015 at 20:09
  • \$\begingroup\$ The period is probably 840 ... good choice of numbers \$\endgroup\$
    – edc65
    Oct 7, 2015 at 20:15
1
\$\begingroup\$

CJam, 281 bytes

99mrqi_])0>=i:A7md{;A2%{S["suggested""insisted on""did"]A2/=+" it"+}{"To "["fool""satisfy"_"please"]A(2/:B=" the "["smart""bald""tall""rich""stupid"]B=SM}?[M"Stewie""Peter""Homer""The programmer""The system manager""You"]A=\'!}{["How should I know?""Stop asking!""Don't ask!"]\(=}?

Permalink

Haven't used CJam before, so I'll take any tips. I'm sure there's a lot of tricks I don't know!

(I couldn't figure out how to name this as a function called "why" - it appears that functions don't exist in CJam - so I'm not sure if a CJam answer is okay or not...)

\$\endgroup\$
1
  • \$\begingroup\$ Functions do exist, but there are only 26 valid function names (A to Z). \$\endgroup\$
    – Dennis
    Oct 8, 2015 at 5:48
1
\$\begingroup\$

Lua 5.3.0, 452 460 446 bytes

This is my first attempt at a code golf, so please correct me if I did something wrong!

a={"Stewie","Peter","Homer","The Programmer","The system manager","You"}b={"fool ","satisfy ",n,"please "}b[3]=b[2]why=function(n)pcall(math.randomseed,n and n>0 and n)n=math.random(1e9)q=n>>4r=n>>8return 1>n&7 and({"How should I Know?","Stop asking!","Don't ask!"})[q%3+1]or 0<n%2 and a[q%6+1]..({" suggested"," insisted on"," did"})[r%3+1].." it"or"To "..b[q%4+1].."the "..({"smart ","bald ","tall ","rich ","stupid "})[r%5+1]..a[(r>>4)%6+1]end

Ungolfed:

a={
    "Stewie",
    "Peter",
    "Homer",
    "The Programmer",
    "The system manager",
    "You"
}
b={
    "fool ",
    "satisfy ",
    n,
    "please "
}
b[3]=b[2]
why=function(n)
    pcall(math.randomseed,n and n>0 and n)
    n=math.random(1e9)
    q=n>>4
    r=n>>8
    return
            1>n&7 and
                ({"How should I Know?","Stop asking!","Don't ask!"})[q%3+1]
            or 0<n%2 and
                a[q%6+1]..({" suggested"," insisted on"," did"})[r%3+1].." it"
            or
                "To "..b[q%4+1].."the "..({"smart ","bald ","tall ","rich ","stupid "})[r%5+1]..a[(r>>4)%6+1]
end
\$\endgroup\$
0
\$\begingroup\$

Python (2), 692 bytes

I’m still learning, so please be gentle! :)

from sys import argv,maxint
import random
def why(*O):
 P=["You","Stewie","Peter","Homer","programmer","system manager"];E=["did","suggested","insisted on","insisted on"];I=["please","fool","satisfy","satisfy"];Q=["stupid","smart","bald","tall","rich"];S=["Don't ask!","How should I know?","Stop asking!"]
 if len(argv)>1:A=O[0]
 else:A=random.randint(-maxint-1,maxint)
 if A%7==0:print S[A%3]
 else:
  M=P[A%6]
  if A%11==0:
   M=P[4]
  if A%2==0:
   if M==P[0]:M="you"
   U=I[(A%8)/2];Z=Q[(A%10)/2];print"To %s the %s %s!"%(U,Z,M)
  if A%2==1:
   if M==P[4]:M="The %s"%P[4]
   if M==P[5]:M="The %s"%P[5]
   C=E[((A+1)/2)%4];print"%s %s it!"%(M,C)
if len(argv)>1:why(int(argv[1]))
else:why()

Works with or without an int as a command line argument.

I tried to emphasise code correctness as much as possible, as with generating random numbers from -sys.maxint - 1 to sys.maxint and displaying sentences in the right case.

The code relies very heavily of if-statements that I’m sure could be replaced with something more place efficient.

Feedback is very welcome!

Ungolfed (1341 bytes)

from sys import argv, maxint
import random

def Why(*Optional):
    Persons = ["You", "Stewie", "Peter", "Homer", "programmer", "system manager"]
    Endings = ["did it", "suggested it", "insisted on it", "insisted on it"]
    Verbs = ["please", "fool", "satisfy", "satisfy"]
    Adjectives = ["stupid", "smart", "bald", "tall", "rich"]
    SpecialCases = ["Don't ask!", "How should I know?", "Stop asking!"]
    
    if len(argv) > 1:
        Argument = Optional[0]
    else:
        Argument = random.randint(-maxint - 1, maxint)
        
    if Argument % 7 is 0:
        print SpecialCases[Argument % 3]
    else:
        Person = Persons[(Argument) % 6]
        if Argument % 11 is 0:
            Person = "programmer"
        if Argument % 2 is 0:
            if Person is "You":
                Person = "you"
            Verb = Verbs[(Argument % 8) / 2]
            Adjective = Adjectives[(Argument % 10) / 2]
            print "To %s the %s %s!" % (Verb, Adjective, Person)
        if Argument % 2 is 1:
            if Person is "programmer":
                Person = "The programmer"
            if Person is "system manager":
                Person = "The system manager"
            Ending = Endings[((Argument + 1) / 2) % 4]
            print "%s %s!" % (Person, Ending)

if len(argv) > 1:
    Why(int(argv[1]))
else:
    Why()
\$\endgroup\$
1
  • 2
    \$\begingroup\$ I suggest you read [codegolf.stackexchange.com/questions/54/…—in particular, you can save many bytes by using the first tip on that page. You can also index from the back of the verb list so you only need one "satisfy": use argument%8/2-1 and remove the second one. You can also replace ==0 with <1. \$\endgroup\$
    – lirtosiast
    Oct 8, 2015 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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