51
\$\begingroup\$

Mr. Mackey is a South Park character well-known for adding "m'kay" in everything he says.

Write a program or function that transforms a string of text into something Mr. Mackey would say.

M'kay placement

  • m'kay has a random 50% chance of being added after the punctuations ,, ., ? and !. If that is the case, it will be followed by the exact same punctuation mark that preceeds it and preceeded by a space.

    For example, in the sentence Test, test., there are two places where m'kay can be added: after the comma, and after the period, with a 50% chance at each place. Possible results would be Test, m'kay, test. or Test, test. M'kay. or Test, m'kay, test. M'kay..

  • There must always be at least one m'kay added. Moreover, it cannot always be at the same place and each valid place where m'kay could be added must occur with equal probability. That is, you can't add m'kay always at the end of the string if because of randomness you never added any m'kay. If there is only one m'kay, it must have the same probability of appearing in each valid position, even though its presence is enforced.

  • If m'kay is after ?, . or !, the m must be uppercased.

  • The number of m in m'kay must be uniformely picked between 1 and 3. That is, m'kay, mm'kay and mmm'kay are all possible choices, each with probability 0.33... If it must be uppercased (see above rule), all m must be uppercased.

Inputs, outputs

  • Inputs are ASCII strings containing characters from ASCII Dec 32 (Space) to ASCII Dec 126 (Tilde ~). There are no linebreaks in the input. You may assumed that any input will contain at least one of , . ? !.

  • You may assume that there are no m'kay or any of its variants in the input.

    Inputs may be taken from STDIN, function arguments, command line, or anything similar.

  • Output may be via STDOUT, a function return, or something similar.

Test cases

  • Input: Test.

Possible output: Test. M'kay.

  • Input: Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Possible output: Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. MMM'kay. It's 100% free, mm'kay, no registration required.

  • Input: Drugs are bad, so, if you do drugs, you're bad, because drugs are bad. They can hurt your body, cause drugs are bad.

Possible output: Drugs are bad, m'kay, so, if you do drugs, you're bad, m'kay, because drugs are bad. They can hurt your body, m'kay, cause drugs are bad. M'kay.

  • Input: Do you understand? Really? Good!

Possible output: Do you understand? MM'kay? Really? Good! MMM'kay!

Scoring

This is , so the shortest code in bytes wins, m'kay?

\$\endgroup\$
  • 10
    \$\begingroup\$ +1, M'kay, but we need a Cartman challenge! \$\endgroup\$ – Level River St Jul 28 '15 at 16:43
  • 16
    \$\begingroup\$ @steveverrill not sure the language in a Cartman challenge would be acceptable here sadly :P \$\endgroup\$ – Fatalize Jul 28 '15 at 16:45
  • 1
    \$\begingroup\$ I want to see an answer in Ook! MM'kay! But you'll probably want to use this algorithm for a pseudo-random number generator. \$\endgroup\$ – mbomb007 Jul 28 '15 at 20:04
  • 3
    \$\begingroup\$ @Fatalize: It's all Kyle's mom's fault. \$\endgroup\$ – marinus Jul 28 '15 at 20:08
  • 4
    \$\begingroup\$ "M'kay has a random 50% chance of being added after the punctuations ,, ., ? and !" seems to be incompatible with "There must always be at least one m'kay added". Please clarify that \$\endgroup\$ – Luis Mendo Jul 28 '15 at 23:58

15 Answers 15

13
\$\begingroup\$

CJam, 65 52 49 bytes

l{_{_",.?!"#:IW>)mr{SI'M'm?3mr)*"'kay"3$}&}%_@=}g

Try it online in the CJam interpreter.

How it works

l            e# Read a line from STDIN.
{            e# Do:
  _          e#   Duplicate the line.
  {          e#   For each of its characters:
    _",.?!"# e#     Find its index in that string.
    :IW>     e#     Save the index in I and check if it's greater than -1.
    )        e#     Add 1 to the resulting Boolean.
     mr      e#     Pseudo-randomly select a non-negative integer below that sum.
             e#     If I == -1 the result will always be 0.
    {        e#     If the result is 1:
      S      e#       Push a space.
      I'M'm? e#       Select 'm' if I == 0 (comma) and 'M' otherwise.
      3mr)   e#       Pseudo-randomly select an integer in [1 2 3].
      *      e#       Repeat the M that many times.
      "'kay" e#       Push that string. MMM'kay.
      3$     e#       Copy the proper punctuation.
    }&       e#
  }%         e#
  _          e#   Copy the resulting array.
  @=         e#   Compare it to the copy from the beginning.
}g           e# Repeat the loop while the arrays are equal.
             e# This makes sure that there's at least one m'kay. M'kay.
\$\endgroup\$
22
\$\begingroup\$

APL (66)

{∊⍉⍵⍪⍉⍪(¯1+⌈?2×⍵∊',.!?')/¨{' ',⍵,⍨'''kay',⍨'mM'[1+⍵≠',']/⍨?3}¨⍵}⍣≢

Result of 10 runs:

      ↑ ({∊⍉⍵⍪⍉⍪(¯1+⌈?2×⍵∊',.!?')/¨{' ',⍵,⍨'''kay',⍨'mM'[1+⍵≠',']/⍨?3}¨⍵}⍣≢)¨ 10/⊂'Test, test. Test! Test?'
Test, m'kay, test. Test! Test?                  
Test, test. M'kay. Test! MMM'kay! Test? M'kay?  
Test, mm'kay, test. Test! MM'kay! Test? MM'kay? 
Test, mmm'kay, test. Test! Test? M'kay?         
Test, mm'kay, test. Test! Test? M'kay?          
Test, test. MM'kay. Test! Test? MMM'kay?        
Test, test. MMM'kay. Test! MMM'kay! Test? M'kay?
Test, test. Test! MM'kay! Test?                 
Test, mm'kay, test. M'kay. Test! Test?          
Test, test. MM'kay. Test! MM'kay! Test?   

Explanation:

  • {...}⍣≢: apply the function to the input until the value changes
    • Generate a M'kay for each character:
    • {...}¨⍵: for each character in the input:
      • 'mM'[1+⍵≠',']/⍨?3: generate 1 to 3 ms or Ms depending on whether the character was a comma or not.
      • '''kay',⍨: append the string 'kay.
      • ⍵,⍨: append the character
      • ' ',: prepend a space.
    • (¯1+⌈?2×⍵∊',.!?')/¨: for each M'kay', if its corresponding character is one of .,!?, select it with 50% chance, otherwise select it with 0% chance.
    • ⍉⍵⍪⍉⍪: match each selection with its character,
    • : list all the simple elements (characters) in order.
\$\endgroup\$
  • \$\begingroup\$ Here's a link to try it online. \$\endgroup\$ – Alex A. Jul 28 '15 at 18:45
  • \$\begingroup\$ Ok, how does this enforce that there is always one added? \$\endgroup\$ – Jerry Jeremiah Jul 29 '15 at 2:07
  • 6
    \$\begingroup\$ @JerryJeremiah: ⍣≢ applies the function repeatedly until the input does not match the output. So if one is added, the output is changed and it stops and returns the output, and if one is not added, the output remains unchanged and it runs again until one is added. \$\endgroup\$ – marinus Jul 29 '15 at 2:09
  • \$\begingroup\$ I missed that somehow. That's very clever. \$\endgroup\$ – Jerry Jeremiah Jul 29 '15 at 4:33
  • 2
    \$\begingroup\$ @DmitryGrigoryev: if you use a traditional APL encoding, it does indeed only take 1 byte. \$\endgroup\$ – marinus Jul 30 '15 at 13:29
9
\$\begingroup\$

K5, 99 90 bytes

{f::0;{x;~f}{,/{f::f|r:(*1?2)&#&",.?!"=x;x,("";" ",((1+1?3)#"Mm"@x=","),"'kay",x)@r}'x}/x}

Well, someone needed to kick-start this!

Saved 9 bytes by using a less fancy method of uppercasing the M.

Explanation

{                                                                                        }  Define a function
 f::0;                                                                                      Set `f` (used to determine when to stop) to 0.
      {x;~f}{                                                                         }/x   While `f` is 0 (no "m'kay"s have been inserted), loop over the string argument
               {                                                                   }'x      For each character in the string
                       (*1?2)&#&",.?!"=x                                                    If we are at a punctuation character, generate a random number between 0 and 1
                     r:                                                                     and assign it to `r`
                f::f|                                                                       If the number is one, an "m'kay" will be inserted, so the outer while loop should exit after this
                                                            "Mm"@x=","                      If the punctuation is a comma, then use a lowecase `m`, otherwise use `M`
                                                    (1+1?3)#                                Repeat the `m` between 1 and 3 times
                                               " ",(                  ),"'kay",x            Join the "m'kay" string to the punctuation and prepend a space
                                         x,("";                                 )@r         If the random number is 1, append the "m'kay" string, to the current string
             ,/                                                                             Join the resulting string

99-byte version

{f::0;{x;~f}{,/{f::f|r:(*1?2)&#&",.?!"=x;x,("";" ",((1+1?3)#`c$(-32*~","=x)+"m"),"'kay",x)@r}'x}/x}
\$\endgroup\$
7
\$\begingroup\$

Julia, mm'kay, 115 114 bytes

f(s)=(R=replace(s,r"[,.?!]",r->r*(" "*(r==","?"m":"M")^rand(1:3)*"'kay"*r)^rand(0:1));ismatch(r"m'kay"i,R)?R:f(R))

This creates a recursive function that accepts a string and returns a string.

Ungolfed + explanation:

function f(s)
    # Replace occurrences of punctuation using random repeats
    R = replace(s, r"[,.?!]", r -> r*(" " * (r == "," ? "m" : "M")^rand(1:3) * "'kay" * r)^rand(0:1))

    # Check whether anything was replaced
    if ismatch(r"m'kay"i, R)
        # If so, return the replaced string
        R
    else
        # Otherwise recurse
        f(R)
    end
end

I dislike South Park, but the thrill of the golf was too enticing to pass this up. Thanks to KRyan for simplifying a regex, saving 1 byte.

\$\endgroup\$
6
\$\begingroup\$

JavaScript ES6, 79 86 108 bytes

Turns out making the M repeat takes a lot of bytes.

(s,z=Math.random)=>s.replace(/([!?.,])/g,l=>z(t=t+1)>=.5||t?` ${(l==','?'m':'M').repeat(0|z()*3+1)}'kay`+l:l)

Old version (doesn't repeat)(86 bytes)

(s,t=1)=>s.replace(/([!?.,])/g,l=>Math.random()>=.5||--t?` ${l==','?'m':'M'}'kay`+l:l)

Older version (doesn't repeat, doesn't require at least one m'kay)(79 bytes):

s=>s.replace(/([!?.,])/g,l=>~~(Math.random()*2)?l+` ${l==','?'m':'M'}'kay`+l:l)

Oldest version:

s=>(r=t=>t.replace(/([!?.])/,"$1 M'kay$1").replace(/,/,", m'kay,"),r(s),[for(i of s)~~(Math.random()*2)?r(i):i].join``)
\$\endgroup\$
  • \$\begingroup\$ Latest version has a ReferenceError: t is not defined \$\endgroup\$ – Neil Jul 29 '15 at 11:03
  • \$\begingroup\$ Only the oldest version actually works on the Test. input. \$\endgroup\$ – Neil Jul 29 '15 at 11:04
  • \$\begingroup\$ @Neil that shouldn't be happening, works just fine for me. Can you add the code you're using in the console \$\endgroup\$ – Downgoat Jul 29 '15 at 16:07
  • \$\begingroup\$ I wrap your submission in parentheses and then suffix ("Test.") to it. \$\endgroup\$ – Neil Jul 29 '15 at 23:52
5
\$\begingroup\$

Pyth, 51 50 49

Saved 1 byte thanks to @Maltysen.

 fnzJsm?&O2}dK",.!?"s[d\ *hO3?xKd\M\m"'kay"d)dz0J

Try it online.

Explanation & more golfing coming soon.

\$\endgroup\$
4
\$\begingroup\$

C, 170 bytes

First crack at it:

n;main(r,v,p)char**v,*p;{for(srand(time(0)),p=v[1];r=rand(),*p;p++)if(strchr(".,?!",putchar(*p))&&r%2||(!*(p+1)&&!n))n=printf(" %.*s'kay%c",r/2%3+1,*p%4?"MMM":"mmm",*p);}

Ungolfed:

n;
main(r,v,p)
char**v,*p;
{
    for(srand(time(0)), p=v[1]; r=rand(), *p; p++) /* loop through string */
        if(strchr(".,?!",putchar(*p)) /* print the char, check if punctuation */
            && r % 2 /* should we say it? */
            || (!*(p+1) && !n)) /* If this is the end of the string and we haven't M'kay'd, then do it now */
            n=printf(" %.*s'kay%c", r/2%3+1, *p%4 ? "MMM" : "mmm", *p); /* say it! */
}
\$\endgroup\$
4
\$\begingroup\$

Scala, 191 bytes

var(r,s,a,o)=(util.Random,readLine,1>2,"")
while(!a){o=""
for(c<-s)o+=(if(",.?!".contains(c)&&r.nextBoolean){a=2>1
s"$c ${(if(c==46)"M"else"m")*(1+r.nextInt(3))}'kay$c"}else s"$c")}
print(o)
\$\endgroup\$
3
\$\begingroup\$

Mathematica, 202 bytes

i=0;r=Random;x=r[];
h=" "<>If[#==",","m","M"]~Table~{Ceiling[3r[]]}<>"'kay"<>#&;
(ee/.a:>(If[e~Count~a@__==i&&#==Floor[x*i],h@#2,""]&))@
StringReplace[#,x:","|"."|"?"|"!":>x~~RandomChoice@{i++~a~x,h@x}]&

Line breaks added for readability. Evaluates to an anonymous function taking the string as an argument. ( is shorthand for \[Function].)

Ungolfed:

h[x_]:=" " <> Table[
    If[x==",", "m", "M"],
    { Ceiling[3 Random[]] }
] <> "'kay" <> x;

h takes a punctuation char and makes it " m'kay,", " mm'kay,", etc. randomly and capitalized appropriately.

f[s_] := (i = 0;
   StringReplace[s, 
    x : "," | "." | "?" | "!" :> 
     x ~~ RandomChoice[{a[i++, x], h[x]}]]);

f takes a string and looks for any punctuation character x; when it finds it, it tacks on with 50% probability the appropriate h[x], and 50% an expression like a[3, x]. It also updates i to the total number of punctuation replaced (with both cases). So f["X, x."] might evaluate to

"X," ~~ h[","] ~~ " x." ~~ a[1, "."]           ...which might expand to
"X, mmm'kay, x." ~~ a[1, "."]                  , and i would equal 2

Finally, g will deal with the a's.

g[expr_] := (r = Random[]; 
  expr /. a -> (If[Count[expr, a[__]] == i && # == Floor[r*i], h[#2], ""] &))

Count will count how many a's we put in there; if it equals i, the total number of punctuation, then we didn't add any m'kays. In this case, we will have expressions like a[0, _] ... a[i-1, _], and we define a so that it'll return an m'kay for exactly one of 0..i-1.

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

Python, 173 168 156

from random import randint as R
    m,k,s,C="mM","'kay",input(),0
    while C<1:
        S=""
        for c in s:r=R(0,c in",.!?");C+=r;S+=c+(' '+m[c!=","]*R(1,3)+k+c)*r
    print(S)

Ungolfed:

from random import randint
m, kay = "mM", "'kay"
string = input()
count = 0
while count < 1: #at least one occurrence
    newString= ""
    for char in s:
        rm  = randint(1,3) #number of "m"
        rmk = randint(0, char in ",.!?") #occurrence of "m'kay"
        count += rmk
        newString += char + (' ' + m[c != ","] * rm + kay + char) * rmk
print(newString)
\$\endgroup\$
  • \$\begingroup\$ Your indentation seems to be pretty messed up :/ \$\endgroup\$ – jazzpi Jul 29 '15 at 9:24
  • \$\begingroup\$ I know, tabs got automatically converted to spaces. \$\endgroup\$ – Trang Oul Jul 29 '15 at 9:53
2
\$\begingroup\$

><>, 150 bytes

i:0(?v
r0&v >
?v~>:0(?v::o1[:::",.?!"{=${=+${=+r=+]
>x~^    >&:0)?;&"."14.
v>&1+&1[:","=&"yak'"&84**"M"+
 >  >84*v
>x::^>22 .
 >: ^]
ol0=?^  >

13 wasted bytes, but I've gotten a little bored trying to rearrange it. Also, randomisation in a Funge is hard to golf -.-

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

Perl, 93 89 88 bytes

$_=$0=<>;s/[.?!]|(,)/$&.($".($1?"m":M)x(1+rand 3)."'kay$&")[rand 2]/ge while$0eq$_;print

Can definitely be golfed some more!

4 bytes cut off thanks to Dom Hastings

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

C++ 290

My solution

void M(string x){
srand(rand());
string p(",.?!");
char c=0,m='m',n='M';
int r=0;
size_t z=0;
for(size_t i=0;i<x.size();i++)
{
c=x[i];cout<<c;
z=p.find(c);
r=rand()%2;
if(z!=string::npos&&r)
{
cout<<' ';
c=(z?n:m);
r=rand()%3+1;
while(r--){cout<<c;}
cout<<"\'kay";
}
}
}

Explanation variable z determines which punctuation mark and z=0 indicates to use 'm' rather than 'M'.

Test

int main()
{
int x=5;
while(x--){
string S("Do you understand? Really? Good! Yes, I do.");
M(S);
cout<<endl;
}
return 0;
}
\$\endgroup\$
  • \$\begingroup\$ string::npos => -1 or ~0. Choosing ~0 lets you use - instead of !=; so that conditional becomes if(z-~0&&r), saving 11 bytes. \$\endgroup\$ – Schism Jul 31 '15 at 16:26
1
\$\begingroup\$

JavaScript ES6, 121 bytes

(s,r=Math.random,f=t=>t==s?f(s.replace(/[!?.,]/g,m=>r()<.5?m:m+" "+(m==","?"mmm":"MMM").slice(r()*3)+"'kay"+m)):t)=>f(s)

Crashes if the given string contains no suitable punctuation.

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

Lua, 162 160 bytes

r=math.random;s,m=io.read()repeat m=s:gsub("([,.?!])",function(p)return p..(r()>.5 and" "..(p==","and"m"or"M"):rep(r(1)).."'kay"..p or"")end)until s~=m;print(m)

Did you ever hear the tragedy of Darth Plagueis The Wise? MM'kay? I thought not. MMM'kay. It’s not a story the Jedi would tell you. M'kay. It’s a Sith legend. Darth Plagueis was a Dark Lord of the Sith, m'kay, so powerful and so wise he could use the Force to influence the midichlorians to create life… He had such a knowledge of the dark side that he could even keep the ones he cared about from dying. MM'kay. The dark side of the Force is a pathway to many abilities some consider to be unnatural. MM'kay. He became so powerful… the only thing he was afraid of was losing his power, mmm'kay, which eventually, mm'kay, of course, m'kay, he did. M'kay. Unfortunately, he taught his apprentice everything he knew, then his apprentice killed him in his sleep. M'kay. Ironic. He could save others from death, but not himself.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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