This challenge is inspired by a series of young children's books by Fiona Watt and Rachel Wells, which I've recently been enjoying with my daughter.

In each book a mouse (illustrated, but not part of the text) complains that a succession of 5 things of the same type are not its thing. It then backs this up by declaring that some component of the thing doesn't have the property it expects.

On the sixth time of asking, the mouse finds its thing and is pleased because it has the expected property.

Here is the text of a typical example:

That's not my bunny, its tail is too fluffy.
That's not my bunny, its paws are too rough.
That's not my bunny, its tail is too woolly.
That's not my bunny, its eyes are too shiny.
That's not my bunny, its nose is too wrinkled.
That's my bunny! Its ears are so soft.

Now, most programming folk would realise that this is a very algorithmic method of producing some text. Because it's such a clear process, we should be able to reproduce this by writing some code.

Let's start with three collections of words:

things = ["dinosaur", "lamb", "princess", "reindeer", "train"]
parts = ["back", "bells", "body", "bows", "crown", "dress", "ears",
  "engine", "fan", "flippers", "funnel", "hooves", "horns", "neck",
  "nose", "roof", "sash", "side", "spines", "spots", "tail", "teeth",
  "tiara", "wheels", "windows"]
properties = ["bumpy", "fluffy", "furry", "fuzzy", "glittery", "glossy",
  "hairy", "red", "rough", "rusty", "shiny", "silky", "slippery", 
  "soft", "sparkly", "squashy", "thick", "velvety", "woolly"]
  • First, we decide which kind of thing we will be describing.
  • Then 5 times, we will generate the line "That's not my [thing], its [part] is too [property].
  • Finally, we generate the line "That's my [thing]! Its [part] is so [property]!

The challenge

  • Generate the text of a "That's not my..." story.
  • It must not consistently reproduce the same text.
  • It's code golf, so attempt to do so in the smallest number of bytes.
  • Use any language you please.
  • White space doesn't matter, but there must be a newline character between lines.
  • The lists of source words are not part of your answer (in TIO they can be added to the header).
  • You can rename the lists of source words.
  • Output can be output to a terminal or text generated into an object.
  • Please include a link to an online interpreter.
  • Ignore plurals, "its horns is" is fine.
  • It doesn't need to make sense. If your princess's funnel is too fluffy, just say so.

Sample output:

That's not my train, its engine is too rusty.
That's not my train, its hooves is too thick.
That's not my train, its sash is too fuzzy.
That's not my train, its tail is too velvety.
That's not my train, its horns is too glittery.
That's my train! Its hooves is so hairy.

Happy golfing!

  • 2
    \$\begingroup\$ @Shaggy The first example is the actual text of one of the books. It’s not a valid answer for this challenge. I’ve said to ignore plurals to simplify the challenge a little. That example is basically background information. \$\endgroup\$
    – AJFaraday
    Jun 9, 2019 at 15:18
  • 1
    \$\begingroup\$ Related \$\endgroup\$ Jun 9, 2019 at 15:20
  • 10
    \$\begingroup\$ You state "It doesn't need to make sense.", does that extend to near-contractions? (i.e. is "That's not my bunny, its eyes are too shiny. ... That's my bunny! Its eyes are so shiny." acceptable as a possible output?) - I'd guess so, just thought I'd check. \$\endgroup\$ Jun 9, 2019 at 16:13
  • 13
    \$\begingroup\$ Aren't "It must not consistently reproduce the same text" and kolmogorov-complexity kind of incompatible? \$\endgroup\$ Jun 9, 2019 at 23:48
  • 2
    \$\begingroup\$ @ChrisH That's my taxonomical mistake. Although both are classed as Glires, so that's something I've learned today. \$\endgroup\$
    – AJFaraday
    Jun 11, 2019 at 8:16

17 Answers 17


Python 3, 149 bytes

lambda a,*l:shuffle(a)or["That's "+s%(a[0],*map(choice,l))for s in["not my %s, its %s is too %s."]*5+["my %s! Its %s is so %s."]]
from random import*

Try it online!

-9 bytes thanks to movatica

  • \$\begingroup\$ Nice work! Shorter tuple syntax: 149 bytes \$\endgroup\$
    – movatica
    Jun 10, 2019 at 9:22
  • 1
    \$\begingroup\$ @movatica Ooh, nice. Thanks! \$\endgroup\$
    – hyper-neutrino
    Jun 10, 2019 at 13:19
  • \$\begingroup\$ "That's not my reindeer, its ears is too bumpy." - needs something to switch between is/are. \$\endgroup\$
    – John Hunt
    Jun 11, 2019 at 15:08
  • 1
    \$\begingroup\$ @JohnHunt the rules say to ignore plurals. \$\endgroup\$
    – hyper-neutrino
    Jun 11, 2019 at 15:51
  • \$\begingroup\$ My mistake. This is v.impressive \$\endgroup\$
    – John Hunt
    Jun 12, 2019 at 10:06

Charcoal, 72 bytes

≔‽θθF⁵«That's not my θ, its ‽η is too ‽ζ.⸿»That's my θ! Its ‽η is so ‽ζ.

Try it online! Link is to verbose version of code. Expects the arrays of things, parts and properties to be in the variables θ, η and ζ, which is most easily arranged by providing them in the input rather than the header. Explanation:


Pick a random thing.

F⁵«That's not my θ, its ‽η is too ‽ζ.⸿»

Print five negative sentences.

That's my θ! Its ‽η is so ‽ζ.

Print the positive sentence.


Japt v2.0a0 -R, 73 bytes

6Æ`Tt's {`not `pT=Y<5}my {+`!,`gT} {73dT*H}ts {Vö}  {`tÑ?`ë2!T} {Wö}.

Takes the three lists as U, V, and W. Those are the default input variables anyways, so just put the three lists in the input section.

Try it

ö                         Saves the random object in variable U
6Æ                        Range [0..6), and map each to the following string
`That's                   The string "That's " plus
{`not `pT=Y<5}            "not " if the index is less than 5 (and store that in variable T), else ""
my                        Literal "my " plus
{+`!,`gT}                 U plus ',' if T, else '!'
{73dT*H}ts                "its " if T, else "Its "
{Vö}                      Random item from V
{`tsooo`ë2!T}             "too" if T, else "so"
{Wö}.                     Random item from V, plus a period
  • \$\begingroup\$ Very nice trick with "too/so" :) \$\endgroup\$
    – Shaggy
    Jun 13, 2019 at 21:41

PowerShell, 147 bytes

This main program will not repeat any part or property in a run, and has reasonable randomization.

$a=$a|Random -c 6
$r=$r|Random -c 6
0..4|%{"That's not my $t, its $($a[$_]) is too "+$r[$_]}
"That's my $t! Its $($a[5]) is so "+$r[5]

Try it online!

Writing get-random so many times costs so many characters! However, unless you are willing to let parts and properties be repeated, I can't see a way to shrink this in powershell any further. Unless you move the first 3 line pipes to the end of the 3 assignment lines in the header. To have something like

# Header
$l = ("dinosaur", "lamb", "princess", "reindeer", "train")|Get-Random
$a = ("back", "bells", "body", "bows", "crown", "dress", "ears",
  "engine", "fan", "flippers", "funnel", "hooves", "horns", "neck",
  "nose", "roof", "sash", "side", "spines", "spots", "tail", "teeth",
  "tiara", "wheels", "windows")|sort{Get-Random}
$r = ("bumpy", "fluffy", "furry", "fuzzy", "glittery", "glossy",
  "hairy", "red", "rough", "rusty", "shiny", "silky", "slippery", 
  "soft", "sparkly", "squashy", "thick", "velvety", "woolly")|sort{Get-Random}

# Main
(1..5)|%{echo("That's not my $t, its "+$a[$_]+" is too "+$r[$_])}
"That's my $t! Its "+$a[6]+" is so "+$r[6]

But that seems like it's cheating, and still doesn't beat Neil's answer.

Edit: Thanks for the tips Matt, and thanks AdmBorkBork for fleshing them out, removing the 3 sets of get- text reduced it to 159 bytes, then some more golf from Adm got it down to 147. The code I was thinking of which allowed duplicates and contradictory statements was 144 characters after applying the same golf tips.

function n{(random 18)+1}
0..4|%{"That's not my $t, its $($a[(n)]) is too "+$r[(n)]}
"That's my $t! Its $($a[$(n)]) is so "+$r[(n)]

Try it online!

However, it not only has a tendency to say the same thing multiple times, but it pretty much requires that your inputs be the same number of elements. I believe the pseudo random number generator being used is heavily dependent on the clock, and quick repeated calls to it can often result in the same result. Then it has the condition that it only uses the whole list if all lists are the same length.With only saving 3~5 characters and having so many caveats, I prefer the code at the start of this post.

  • 1
    \$\begingroup\$ Welcome to PPCG! Parts and properties can be repeated so that should save you some bytes. \$\endgroup\$
    – Shaggy
    Jun 10, 2019 at 9:51
  • 2
    \$\begingroup\$ You can drop the Get- from Get-Random. Its the default verb tested when evaluating commands. \$\endgroup\$
    – Matt
    Jun 10, 2019 at 12:20
  • 2
    \$\begingroup\$ Welcome! Some easy golfs gets you down to 147 bytes \$\endgroup\$ Jun 10, 2019 at 13:32

Jelly, 72 bytes


Try it online!


JavaScript, 129

(a,b,c)=>(z='',a.forEach((f,i)=>z+=`That's ${q=i!=5?"not ":""}my ${f}${q?", i":"! I"}ts ${b[i]} is ${q?"to":"s"}o ${c[i]}.\n`),z)

input is three arrays, returns string


Ruby, 128 bytes

->a,*l{t=a.sample;6.times{|i|puts"That's#{' not'if i<5} my #{t}#{i<5?', i':'! I'}ts %s is #{i<5?'to':?s}o %s."%l.map(&:sample)}}

Try it online!


C#, 204 203 bytes

()=>{int a(int x)=>new Random().Next(x);var j=t[a(5)];string s()=>$"That's not my {j}, its {p[a(25)]} is too {o[a(19)]}.\n";return s()+s()+s()+s()+s()+$"That's my {j}! Its {p[a(25)]} is so {o[a(19)]}.";};

It is my first answer on this site, so I hope it works well. It also needs those three things, but according to question those do not count:

   var t = new[] { "dinosaur", "lamb", "princess", "reindeer", "train" };
   var p = new[] {"back", "bells", "body", "bows", "crown", "dress", "ears",
          "engine", "fan", "flippers", "funnel", "hooves", "horns", "neck",
          "nose", "roof", "sash", "side", "spines", "spots", "tail", "teeth",
          "tiara", "wheels", "windows" };
   var o = new[] {"bumpy", "fluffy", "furry", "fuzzy", "glittery", "glossy",
          "hairy", "red", "rough", "rusty", "shiny", "silky", "slippery",
          "soft", "sparkly", "squashy", "thick", "velvety", "woolly"};

Try it online!

One less byte thanks to Sok.

  • 1
    \$\begingroup\$ Welcome to PPCG! I've taken the liberty of editing in a link to TIO into your answer, so that others can easily try your code for themselves - I would have given you the link to it in this comment, but the URI was too long unfortunately! I hope you enjoy your stay :o) \$\endgroup\$
    – Sok
    Jun 11, 2019 at 11:58
  • 1
    \$\begingroup\$ One small golf for you as well - the \r isn't required, which will save you 2 bytes. \$\endgroup\$
    – Sok
    Jun 11, 2019 at 12:01

05AB1E, 63 bytes

ΩU6F€Ω`XN5Qi“€Š's€¯ ÿ!€ç ÿ€ˆ€Ê ÿ.“ë“€Š's€–€¯ ÿ,€ç ÿ€ˆ…« ÿ.“}.ª,

Try it online.

68 bytes version which doesn't output duplicated parts nor properties:

ΩUε.r6£}øεXª`N5Qi“€Š's€¯ ÿ!€ç ÿ€ˆ€Ê ÿ.“ë“€Š's€–€¯ ÿ,€ç ÿ€ˆ…« ÿ.“}.ª,

Try it online.

Both programs assumes the list of things is the first input, and a list containing the list of parts and list of properties is the second input.


Ω            # Pop and push a random element of the things-list
 U           # Pop and store it in variable `X`
  6F         # Loop 6 times:
    €Ω       #  Get a random element from both the parts and properties list
      `      #  Push them to the stack
       X     #  And also push variable `X`
             #  (the order on the stack is now: property, part, thing)
    N5Qi     #  If it's the last iteration:
        “€Š's€¯ ÿ!€ç ÿ€ˆ€Ê ÿ.“ 
            '#   Push dictionary string "that's my ÿ! its ÿ is so ÿ."
       ë     #  Else:
        “€Š's€–€¯ ÿ,€ç ÿ€ˆ…« ÿ.“
            '#   Push dictionary string "that's not my ÿ, its ÿ is too ÿ."
             #  (where the `ÿ` are automatically replaced with the words on the stack)
       }.ª   #  After the if-else: sentence-capitalize the strings
             #  (so the "That's " as well as the "! Its")
          ,  #  And output it with trailing newline

ΩU           # Pop and store a random thing in variable `X`
  ε          # Map the list of lists of parts/properties to:
   .r        #  Shuffle the list
     6£      #  And leave the first six elements
  }ø         # After the map: zip/transpose to create pairs of part & property
    ε        # Foreach over the pairs:
     `XN5Qi“€Š's€¯ ÿ!€ç ÿ€ˆ€Ê ÿ.“ë“€Š's€–€¯ ÿ,€ç ÿ€ˆ…« ÿ.“}.ª,
             #  And the rest of the code is the same as above

See this 05AB1E tip of mine (section How to use the dictionary?) to understand why “€Š's€¯ ÿ!€ç ÿ€ˆ€Ê ÿ.“ is "that's my ÿ! its ÿ is so ÿ." and “€Š's€–€¯ ÿ,€ç ÿ€ˆ…« ÿ.“ is "that's not my ÿ, its ÿ is too ÿ.".


APL (Dyalog Unicode), 117 bytesSBCS

↑('That''s not my ',(t←T⊃⍨?5),', its ')∘,¨P[5?25],¨' is too '∘,¨V[5?19]
'That''s my ',t,'! Its',P[?25],'is so',V[?19]

Try it online!

?N generates a random index among the first N indices.

M?N generates M random indices (without replacement) among the first N indices.

, is concatenation

t←T⊃⍨… picks a random thing and calls it t for reuse in the last line.

∘,¨ concatenates the string on the left to each string on the right.

concatenates each string on the left to each string on the right.

 changes the list of strings into a character matrix so it prints right.


Pyth, 88 78 76 bytes


."b[?d" not"kJ?d", i""! I"OG?d\s"to"OH)6

Try it online!

The code presented above requires the following header:


There's a small issue with using the 'Header' feature in TIO with Pyth, as it looks like TIO joins the code blocks on newlines, and newlines are significant in Pyth. Here is a link to the same code using the 'Header' block, with a junk line in the output.

JONj_ms.ic"That's¶ my ¶¶ts ¶ is ¶o ¶."b[?d" not"kJ?d", i""! I"OG?d"to"\sOH)6   Newlines replaced with ¶
                                                                               Implicit: k="", b=newline
                                                                               From header: N=things, G=parts, H=properties
JON                                                                            Choose a random element from N, store in J
     m                                                                     6   Map [0-6), as d, using:
                                        ?d" not"k                                If d is truthy (i.e. not 0), yield " not", else ""
                                                 J                               J (the chosen thing)
                                                  ?d", i""! I"                   ", i" if d else "! I"
                                                              OG                 Random element from G
                                                                ?d"to"\s         "to" if d else "s"
                                                                        OH       Random element from H
                                       [                                  )      Wrap the previous 6 results in an array
         c"That's¶ my ¶¶ts ¶ is ¶o ¶."b                                          Split the template string on newlines
       .i                                                                        Interleave the template string elements with the previous list
      s                                                                          Concatenate
    _                                                                          Reverse lines
   j                                                                           Join on newlines, implicit print

Edit: Rewrite to golf 10 bytes, previous version: J+" my "ONV5%"That's not%s, its %s is too %s."[JOGOH;%"That's%s! Its %s is so %s."[JOGOH


Perl 5.10, 127 bytes

Run with perl -M5.010 -f filename.pl.

my @t = qw(dinosaur lamb princess reindeer train);
my @r = qw(back bells body bows crown dress ears engine fan flippers funnel
           hooves horns neck nose roof sash side spines spots tail teeth tiara
           wheels windows);
my @p = qw(bumpy fluffy furry fuzzy glittery glossy hairy red rough rusty shiny
           silky slippery soft sparkly squashy thick velvety woolly);

sub r{rand@_}$a=" my $t[r@t]";say"That's not$a, its $r[r@r] is too $p[r@p]."for(1..5);say"That's$a! Its $r[r@r] is so $p[r@p]."

JavaScript ES6, 149 (+15?) bytes

a = ["dinosaur", "lamb", "princess", "reindeer", "train"]
b = ["back", "bells", "body", "bows", "crown", "dress", "ears",
  "engine", "fan", "flippers", "funnel", "hooves", "horns", "neck",
  "nose", "roof", "sash", "side", "spines", "spots", "tail", "teeth",
  "tiara", "wheels", "windows"]
c = ["bumpy", "fluffy", "furry", "fuzzy", "glittery", "glossy",
  "hairy", "red", "rough", "rusty", "shiny", "silky", "slippery", 
  "soft", "sparkly", "squashy", "thick", "velvety", "woolly"]

// r=x=>x[parseInt(Math.random()*x.length)] 164 for better random on fast pc

r=x=>x[new Date%x.length]
g=j=>console.log(`That's ${j?`not my ${s}, its ${r(b)} is to`:`my ${s}! Its ${r(b)} is s`}o ${r(c)}.`)

  • \$\begingroup\$ Welcome to Code Golf! Good work! \$\endgroup\$
    – AJFaraday
    Jun 11, 2019 at 12:48
  • 1
    \$\begingroup\$ Thank's AJ! Appreciate the welcome :) \$\endgroup\$
    – Onitz
    Jun 11, 2019 at 20:12

Batch File, 434 424 + 7 bytes

Executed via cmd/q/c.

Code not counted

set a=dinosaur lamb princess reindeer train
set b=back bells body bows crown dress ears engine fan flippers funnel hoobes horns neck nose roof sash side spines spots tail teeth tiara wheels windows
set c=bumpy fluffy furry fizzy glittery glossy hair red rough rusty shiny silky slippery soft sparkly squashy thick velvety woolly

Code counted

set q=random
set m=set/ar=1+%%%q%%%%%%%
call %m%5
for /f "tokens=%r%" %%x in ("%a%")do set x=%%x
call %m%25
for /f "tokens=%r%" %%y in ("%b%")do set y=%%y
call %m%19
for /f "tokens=%r%" %%z in ("%c%")do echo That's not my %x%, its %y% is too %%z.
if %d% neq 5 goto a
call %m%25
for /f "tokens=%r%" %%y in ("%b%")do set y=%%y
call %m%19
for /f "tokens=%r%" %%z in ("%c%")do echo That's my %x%! Its %y% is so %%z.

I'll go through some challenges you must face and explain/justify what I did so others can improve.

Choose a random element from an array
I did this by generating a random number between 1 and n where n is the amount of elements in that array. I then used this random number as the token to grab in each for loop (tokens=%r%). Because I did it this way, I could not nest these for loops anymore, as tokens=!r! was not working for me (with delayed expansion). This would've saved quite a few bytes as it would've removed the need to save the tokens as variables (set x=%%x).

Random number generation
m is my random number generation macro. Doing it this way saves 32 bytes over doing it like set/ar=%random%%%n+1 every line. You could semi-cheat and decide that tokens y and z are to be the same element:

call %m%19
for /f "tokens=%r%" %%y in ("%b%")do set y=%%y
for /f "tokens=%r%" %%z in ("%c%")do echo That's not my %x%, its %y% is too %%z.

This would, while still retaining some randomness, exclude the final 6 elements of c. This would save a minimum of 20 bytes, but I don't think this is true to the op's requirements.

Theoretical Improvements
I spent quite a while trying to make this "pseudo-code" work, while still saving bytes:

set 1-5=echo That's not my %x%, its %y% is too %%z.
set 6=echo That's my %x%! Its %y% is so %%z.
for /f "tokens=%r%" %%z in ("%c%")do call %%d%%

Unfortunately the setup for this is proving to take up way too many bytes to be profitable (have to implement in < 144 bytes) but I can't shake the feeling that adding the last 4 lines of code are superfluous and janky.

  • \$\begingroup\$ You're not allowed to take inputs via pre-defined variables. You'll have to take it in as actual input through any of the standard IO methods \$\endgroup\$
    – Jo King
    Jun 11, 2019 at 5:51
  • 1
    \$\begingroup\$ @JoKing From the challenge: The lists of source words are not part of your answer (in TIO they can be added to the header). \$\endgroup\$ Jun 11, 2019 at 16:28
  • \$\begingroup\$ I'm unsure if it is allowed or not as I have seen it done both ways in other answers, but for those of you curious it would add 29 bytes to my answer in the form of set a=%~1, etc. \$\endgroup\$
    – BDM
    Jun 11, 2019 at 21:31

ink, 119 bytes

-(l)That's{l<6: not} my {a}{l<6:, i|! I}ts {LIST_RANDOM(b)} is {l<6:to|s}o {LIST_RANDOM(c)}

With the lists defined as

LIST a=(dinosaur),(lamb),(princess),(reindeer),(train)
LIST b=(back),(bells),(body),(bows),(crown),(dress),(ears),(engine),(fan),(flippers),(funnel),(hooves),(horns),(neck),(nose),(roof),(sash),(side),(spines),(spots),(tail),(teeth),(tiara),(wheels),(windows)
LIST c=(bumpy),(fluffy),(furry),(fuzzy),(glittery),(glossy),(hairy),(red),(rough),(rusty),(shiny),(silky),(slippery),(soft),(sparkly),(squashy),(thick),(velvety),(woolly)

Try it online!

Though depending on what counts as a list, there are other approaches. If a list can be a function that randomly returns a list item, the following approach is only 91 bytes:

~temp t=u()
-(l)That's{l<6: not} my {t}{l<6:, i|! I}ts {p()} is {l<6:to|s}o {q()}

(with the "lists" defined as follows)

==function u
~return "{~dinosaur|lamb|princess|reindeer|train}"
==function p
~return "{~back|bells|body|bows|crown|dress|ears|engine|fan|flippers|funnel|hooves|horns|neck|nose|roof|sash|side|spines|spots|tail|teeth|tiara|wheels|windows}"
==function q
~return " {~bumpy|fluffy|furry|fuzzy|glittery|glossy|hairy|red|rough|rusty|shiny|silky|slippery|soft|sparkly|squashy|thick|velvety|woolly}."

Try it online!

There's also the following approach.

~temp t="{~dinosaur|lamb|princess|reindeer|train}"
-(l)That's{l<6: not} my {t}{l<6:, i|! I}ts {~back|bells|body|bows|crown|dress|ears|engine|fan|flippers|funnel|hooves|horns|neck|nose|roof|sash|side|spines|spots|tail|teeth|tiara|wheels|windows} is {l<6:to|s}o {~bumpy|fluffy|furry|fuzzy|glittery|glossy|hairy|red|rough|rusty|shiny|silky|slippery|soft|sparkly|squashy|thick|velvety|woolly}

Try it online!

This solution is 389 bytes, but if the shuffle literals (which in this scenario can't really be moved) count as list definitions and can be excluded from the byte count, this drops to 80 bytes.


Bash +awk, 209 bytes

T=$(shuf $1|head -1)
join <(sed "s/.*/$T\t&/" $2) <(sed "s/.*/$T\t&/" $3)|shuf|awk 'NR<6{printf "That'\''s not my %s, its %s is too %s.\n",$1,$2,$3}NR==6{printf "That'\''s my %s! Its %s is so %s.\n",$1,$2,$3}'

Try it online!

Accepts inputs as things parts properties where each is a file with one item per line of the desired type.

This is a file-centered approach. May try an array-centered approach later to see if it can be improved.


Python 3, 130 bytes

Taking your requirements literally, and taking carriage returns to be one byte each:

def x():
    global y
    print(("That's not my lamb, it's "+b[0:1][y]+" is too red\n")*5+"That's my lamb! Its fan is so red")
  • \$\begingroup\$ "It must not consistently reproduce the same text." From what I can tell, your code will always alternate between one of two options, which seems like consistent output to me. Also, this case of always using the same properties on every single line has been explicitly disallowed in the comments clarifications. \$\endgroup\$
    – Value Ink
    Jun 10, 2019 at 22:01

Your Answer

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

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