A code golf challenge, m'kay

51

6

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?

Fatalize

Posted 2015-07-28T16:26:37.690

Reputation: 32 976

10+1, M'kay, but we need a Cartman challenge! – Level River St – 2015-07-28T16:43:37.983

16@steveverrill not sure the language in a Cartman challenge would be acceptable here sadly :P – Fatalize – 2015-07-28T16:45:43.743

1

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.

– mbomb007 – 2015-07-28T20:04:24.997

3@Fatalize: It's all Kyle's mom's fault. – marinus – 2015-07-28T20:08:32.110

4"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 – Luis Mendo – 2015-07-28T23:58:10.300

Does this "The number of m in m'kay must be uniformely picked between 1 and 3... Mean that all M'kay's in a sentence should have the same number of M's? Because your example outputs for "Programming puzzles...." and "Do you understand...." do not appear to follow this rule. Please clarify what you mean. – CBRF23 – 2015-07-29T03:57:39.600

Is a capitalized M'kay valid at the start of the string? – Winny – 2015-07-29T04:41:44.550

@Winny No, it's not valid. – Fatalize – 2015-07-29T06:08:36.520

@LuisMendo I don't see how it can be clearer. There's a 50% chance for each m'kay but at least one must be enforced regardless of the 50% chance. – Fatalize – 2015-07-29T06:12:19.020

@CBRF23 No, it, the number of m is independant between each m'kay. – Fatalize – 2015-07-29T06:13:06.583

In the first test case, shouldn't the program always produce the same output, given that at least one m'kay is required and they can only appear after punctuation? ie, *"Only possible output: Test. M'kay." – Adam Davis – 2015-07-29T19:58:56.740

@AdamDavis The m'kay will indeed always be there but the number of M's can vary from one to three – Fatalize – 2015-07-29T19:59:42.540

1@Fatalize Mmm'kay! – Adam Davis – 2015-07-29T20:00:17.730

Can the input include m'kay, and if yes, would returning the input as the output (i.e. it includes at least one m'kay but did not add any) pass? I saw at least one answer that checked for the presence of m'kay to determine whether it had randomly added at least one, but that approach would fail if the input started with at least one m'kay. – KRyan – 2015-07-30T18:12:27.913

@KRyan It's ok to assume that there are no m'kay in the input. – Fatalize – 2015-07-30T19:01:18.270

@Fatalize OK, then that should probably be in the question. – KRyan – 2015-07-30T19:02:34.797

1A way of demonstrating the incompatibility mentioned by @LuisMendo would be to consider a string with only one punctuation mark. – Cameron Martin – 2015-08-03T18:28:14.367

Answers

13

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.

Dennis

Posted 2015-07-28T16:26:37.690

Reputation: 196 637

22

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.

marinus

Posted 2015-07-28T16:26:37.690

Reputation: 30 224

Here's a link to try it online. – Alex A. – 2015-07-28T18:45:06.590

Ok, how does this enforce that there is always one added? – Jerry Jeremiah – 2015-07-29T02:07:11.647

6@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. – marinus – 2015-07-29T02:09:42.967

I missed that somehow. That's very clever. – Jerry Jeremiah – 2015-07-29T04:33:50.913

How is this code 66 bytes? Do you consider an to take 1 byte? M'kay? – Dmitry Grigoryev – 2015-07-30T07:02:22.700

2@DmitryGrigoryev: if you use a traditional APL encoding, it does indeed only take 1 byte. – marinus – 2015-07-30T13:29:25.397

9

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}

kirbyfan64sos

Posted 2015-07-28T16:26:37.690

Reputation: 8 730

7

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.

Alex A.

Posted 2015-07-28T16:26:37.690

Reputation: 23 761

6

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``)

Downgoat

Posted 2015-07-28T16:26:37.690

Reputation: 27 116

Latest version has a ReferenceError: t is not defined – Neil – 2015-07-29T11:03:33.490

Only the oldest version actually works on the Test. input. – Neil – 2015-07-29T11:04:40.987

@Neil that shouldn't be happening, works just fine for me. Can you add the code you're using in the console – Downgoat – 2015-07-29T16:07:52.817

I wrap your submission in parentheses and then suffix ("Test.") to it. – Neil – 2015-07-29T23:52:47.940

5

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.

PurkkaKoodari

Posted 2015-07-28T16:26:37.690

Reputation: 16 699

4

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! */
}

Cole Cameron

Posted 2015-07-28T16:26:37.690

Reputation: 1 013

4

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)

triggerNZ

Posted 2015-07-28T16:26:37.690

Reputation: 251

3

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.

jcai

Posted 2015-07-28T16:26:37.690

Reputation: 973

2

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

Jarmex

Posted 2015-07-28T16:26:37.690

Reputation: 2 045

2

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)

Trang Oul

Posted 2015-07-28T16:26:37.690

Reputation: 656

Your indentation seems to be pretty messed up :/ – jazzpi – 2015-07-29T09:24:11.103

I know, tabs got automatically converted to spaces. – Trang Oul – 2015-07-29T09:53:13.157

2

><>, 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 -.-

Sok

Posted 2015-07-28T16:26:37.690

Reputation: 5 592

2

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;
}

bacchusbeale

Posted 2015-07-28T16:26:37.690

Reputation: 1 235

string::npos => -1 or ~0. Choosing ~0 lets you use - instead of !=; so that conditional becomes if(z-~0&&r), saving 11 bytes. – Schism – 2015-07-31T16:26:23.027

1

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.

Blab

Posted 2015-07-28T16:26:37.690

Reputation: 451

1

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.

Neil

Posted 2015-07-28T16:26:37.690

Reputation: 95 035