Generate a Pronounceable Nonsense Word \$n\$ syllables long

15

3

Your task is to generate a nonsense word that is reasonably pronounceable with the specified number of 'syllables'. Each time the program is run possibly results in a different nonsense word.

Pronounceability

A pronounceable word is made up of syllables, which are in turn made up of a vowel group that is possibly sandwiched between two consonant groups. Not all sounds are pronounceable in all positions, and since this depends on the language, we'll use patterns understandable to English speakers

Starting consonant groups:

b c d f g h j k l m n p r s t v w y z bl br ch cl cr dr fl fr gh gl gn gr kn ph pl pr qu sc sh sk sl sm sn sp st th tr wh wr sch scr shm shr squ str thr

Vowel Groups:

a e i o u ae ai ao au ea ee ei eu ia ie io oa oe oi oo ou ue ui

Ending Consonant groups:

b c d f g l m n p r s t x z bt ch ck ct ft gh gn lb ld lf lk ll lm ln lp lt mb mn mp nk ng nt ph pt rb rc rd rf rg rk rl rm rn rp rt rv rz sh sk sp ss st zz lch lsh lth rch rsh rst rth sch tch

Combining Syllables

Both starting and ending consonant groups are optional in general, however you cannot place a syllable ending with a vowel immediately before one starting with a vowel.

Disclaimer

In the interest of simplicity, certain English words can't actually be generated this way, such as vacuum, xylophone, mnemonic, pterodactyl, beautiful, blah, they, wow, and most plurals.

Overview

Possible syllable patterns using this key:

(SC) = starting consonant; (V) = vowel group; (EC) = ending consonant

For one syllable:

  • (SC)(V)(EC)
  • (V)(EC)
  • (SC)(V)
  • (V)

With two syllables:

  • (SC)(V)(EC)(SC)(V)(EC)
  • (SC)(V)(EC)(SC)(V)
  • (SC)(V)(EC)(V)(EC)
  • (SC)(V)(EC)(V)

  • (SC)(V)(SC)(V)(EC)

  • (SC)(V)(SC)(V)

  • (V)(EC)(SC)(V)(EC)

  • (V)(EC)(SC)(V)
  • (V)(EC)(V)(EC)
  • (V)(EC)(V)

  • (V)(SC)(V)(EC)

  • (V)(SC)(V)

... and so on

Examples

1 syllable

  • charst
  • tigh
  • shriegn
  • eess
  • shue
  • oo
  • cheezz

2 syllables

  • jazzcrap
  • whylprog
  • eating
  • umba
  • ola
  • have
  • ingsoc
  • greespheurz
  • bleuspoo

3 syllables

  • brokiompic
  • squirdshlicker
  • capital
  • opengtrass
  • doublethink
  • bigbrother
  • phoebliaptmoo
  • skolfblauquent

4 syllables

  • strawishoepick
  • patchworkzombie
  • prearneajoomie
  • slephotoschou
  • doubleplusgood

Coding

Input: an integer for the number of syllables to generate

Output: a (probably) nonsense word that many syllables long

Rules

  • Some form of (psuedo)randomness is required. All combinations of syllables should be (theoretically) possible to generate, though the distribution does not have to be uniform.
    • You may assume that your generator is aperiodic, so it doesn't have to be mathematically possible to generate every possible word (It might not have a long enough period in reality) and you don't need to provide any sort of proof that your generator can, in fact, produce every possible word.
    • Your generator must actually be able to produce at least 255 distinct values, so you can't just return 4 every time the generator is called.
    • What's ultimately important is that you somehow include all the above letter groups in your code, that each letter group has a nonzero probability of being picked, and each syllable pattern has a nonzero probability of occurring (if provided with true randomness).
  • You must support up to 16 syllable words
  • In addition to the rules on combining syllables, the output word must not have:
    • 3 consecutive vowels (a e i o u; this can happen for qu words)
    • 3 consecutive matching consonants

Good luck!


Note that this is distinct from Generate a pronounceable word for a few reasons:

  • Variable number of syllables specified by input rather than a strict 10-letter requirement.
  • This challenge adds non-exhaustive letter groups that must be (cleverly) encoded and allows for more variants of syllables, so code can't just be copied from the other challenge
  • Squirdshlicker. Need I say more?

I also forgot to dupe check, but it turns out this brings enough new to the table that it doesn't matter. After all, there are hundreds of quine variant challenges.

Beefster

Posted 2019-04-22T23:38:54.407

Reputation: 6 651

2"I also forgot to dupe check, but it turns out this brings enough new to the table that it doesn't matter." Did someone confirm this? I feel like this isn't always true... – Quintec – 2019-04-23T00:22:11.837

2Downvoted for the large amount of "hardcodedness" required given your 3 long lists of consonants and vowels – Stephen – 2019-04-23T01:55:01.777

1Suggest adding doubleplusgood as an example, to match the quality of this challenge. – None – 2019-05-17T14:38:56.203

1Why not "squirdschlicker"? Gotta beat "strengths" on consecutive consonants :) – Punintended – 2019-05-17T16:20:01.333

Answers

4

JavaScript (ES6),  407  403 bytes

f=n=>/[aeiou]{3}|(.)\1\1/.test(s=(h=k=>k?(g=s=>p=s.match(/.[a-z]*/g)[Math.random()*99|0]||(s>x&&p?'':g(s)))(x+'lBrClCrDrFlFrGlGrHJKKnPlPrQuScScrShmShrSlSmSnSquStrThThrTrVWWhWrY')+g('AAeAiAoAuEEaEeEiEuIIaIeIoOOaOeOiOoOuUUeUi')+g(x+'tCkCtFtLbLchLdLfLkLlLmLnLpLshLtLthMbMnMpNgNkNtPtRbRcRchRdRfRgRkRlRmRnRpRshRstRtRthRvRzSsTchXZz')+h(k-1):'')(n,p=x='BCChDFGGhGnLMNPPhRSSchShSkSpStTZB').toLowerCase())?f(n):s

Try it online!

Arnauld

Posted 2019-04-22T23:38:54.407

Reputation: 111 334

Are you sure the [^aeiou]{3} is correct? Based on the word 'matching' and the 3-syllable example squirdshlicker containing rdshl, I think OP only means 3 of the same adjacent consonants (i.e. bbb isn't allowed), instead of 3 adjacent consonants in general. – Kevin Cruijssen – 2019-04-23T10:00:49.297

2@KevinCruijssen On second reading of the challenge, I think there's little doubt that your interpretation is correct. So I've updated my code accordingly. – Arnauld – 2019-04-23T10:40:56.627

3

05AB1E, 237 234 230 228 bytes

.•O0¦"ÐD›ô:ΓF9—∊‘àÕGÌ•3LŽZв₂в×S£V[1U.µ\µTΩiY.•1θ₆Ω–¸‡ÊΔιÃмº³ô»ÝAïG3_@|å“₄bÒs₃l¬t©ïÙK:≠•3LŽII₂в×S£«Ω1U}XižM•·Áy&ŒGηΩ¼αŸKq•6вèJ•Λ1"•bS>£Ω¼0U}TΩiY.•E–æƵHl¨åñyBY±(ú,ā]JùË‚aEuŒ—[K³|C~ôÙŸ„#¼ÑûĀdš+¢zsÄΘä¹ÊÌ₅ôθ•3LŽAE₆в×S£«Ω1U}J}Dγ€g3‹P#

-2 byte thanks to @MagicOctopusUrn.

Try it online or get a few more outputs.

Explanation:

.•O0¦"ÐD›ô:ΓF9—∊‘àÕGÌ•
                  "# Push compressed string "bcdfglmnprstzchghgnphshskspstsch"
  3L               # Push list [1,2,3]
    ŽA;            # Push compressed integer 8997
       ₂в          # Converted to Base-26 as list: [13,8,1]
         ×         # Repeat the digits [1,2,3] that many times: ["1111111111111","22222222","3"]
          S        # Convert it to a list of flattened digits
           £       # Split the string into parts of that size
            V      # Pop and store this string-list in variable `Y`
[                  # Start an infinite loop:
 1U                #  Reset variable `X` to 1
 .µ                #  Reset the counter_variable to 0
 \                 #  Discard the top of the stack (if any)
 µ                 #  Loop while the counter_variable is not equal to the (implicit) input:
  TΩi              #   If a random boolean is truthy:
     Y             #    Push the string-list we stored in variable `Y`
     .•1θ₆Ω–¸‡ÊΔιÃмº³ô»ÝAïG3_@|å“₄bÒs₃l¬t©ïÙK:≠•
                   #    Push compressed string "hjkvwyblbrclcrdrflfrglgrknplprquscslsmsnthtrwhwrscrshmshrsqustrthr"
       3L          #    Push list [1,2,3]
         ŽII       #    Push compressed integer 4608
            ₂в     #    Converted to Base-26 as list: [6,21,6]
              ×    #    Repeat the digits [1,2,3] that many times: ["111111","222222222222222222222","333333"]
               S   #    Convert it to a list of flattened digits
                £  #    Split the string into parts of that size
     «             #    Merge it with list `Y`
      Ω            #    Pop and push a random starting consonant group from this list
     1U            #    And set variable `X` to 1
    }              #   Close the if-statement
  Xi               #   If variable `X` is 1:
    žM             #    Push builtin string "aeiou"
      •·Áy&ŒGηΩ¼αŸKq•
                   #    Push compressed integer 13814931869773709280202935082102
        6в         #    Converted to Base-6 as list: [1,0,1,1,1,2,1,4,0,1,0,2,0,3,0,4,2,0,2,1,2,3,3,0,3,1,3,2,3,3,3,4,4,1,4,2,0,1,2,3,4]
          èJ       #    Index each into the string "aeiou", and join together: "aeaiaoaueaeeeieuiaieiooaoeoiooouueuiaeiou"
      •Λ1"•       "#    Push compressed integer 8388576
           b       #    Converted to binary: "11111111111111111100000"
            S>     #    Split into a list of digits, and each increased by 1
              £    #    Split the string into parts of that size
               Ω   #    Pop and push a random vowel group from this list
    ¼              #    Increase the counter_variable by 1
    0U             #    And then set variable `X` to 0
   }               #   Close the if-statement
  TΩi              #   If a random boolean is truthy:
     Y             #    Push the string-list we stored in variable `Y`
     .•E–æƵHl¨åñyBY±(ú,ā]JùË‚aEuŒ—[K³|C~ôÙŸ„#¼ÑûĀdš+¢zsÄΘä¹ÊÌ₅ôθ•
                   #    Push compressed string "xbtckctftlbldlflklllmlnlpltmbmnmpnkngntptrbrcrdrfrgrkrlrmrnrprtrvrzsszzlchlshlthrchrshrstrthtch"
       3L          #    Push list [1,2,3]
         ŽAE       #    Push compressed integer 2564
            ₆в     #    Converted to Base-36 as list: [1,35,8]
              ×    #    Repeat the digits [1,2,3] that many times: ["1","222...222","33333333"]
               S   #    Convert it to a list of flattened digits
                £  #    Split the string into parts of that size
     «             #    Merge it with list `Y`
      Ω            #    Pop and push a random ending consonant group from this list
     1U            #    And set variable `X` to 1
    }              #   Close the if-statement
  J                #   Join all strings on the stack together
 }D                #  After the while-loop: duplicate the resulting string
   γ               #  Split the copy into chunks, with adjacent characters that are
                   #  the same grouped together
    €g             #  Get the length of each chunk
      3‹           #  Check for each length if it's smaller than 3
        P          #  Check if all are truthy by taking the product, and if it is:
         #         #   Stop the infinite loop
                   # (after which the string at the top of the stack is output implicitly)

See this 05AB1E tip of mine (section How to compress strings not part of the dictionary?, How to compress large integers?, and How to compress integer lists?) to understand how the compression parts works.

Kevin Cruijssen

Posted 2019-04-22T23:38:54.407

Reputation: 67 575

1

Also žM•ô#‰¦λu¢!¡°gU€•6BS<èJ is 4 smaller than .•!m1±P1Ÿ6ºZ dâ4∍m–G¢”ãÔ2g• (base 6 conversion and replacement using built-in for AEIOU). TIO Link too long.

– Magic Octopus Urn – 2019-05-02T17:50:20.143

@MagicOctopusUrn Thanks! And saved 2 more bytes with žM•·Áy&ŒGηΩ¼αŸKq•6вèJ. :) PS: You can use url shorteners like https://tinyurl.com/ on PPCG, unlike most other SE's. :)

– Kevin Cruijssen – 2019-05-03T07:45:42.990

1

Jelly, 231 bytes

e€ØẹŒrḢƇ,ŒɠF>2Ẹ
“yŒʠT¬ḅɼṬɦṀUżGv¶æɲCĊQ>ṙȦẇɼṄ0IḤhDẋDċṀĊṪɗĖƇẊ;1JƒṾỊżỵhṖ8>Ȯ⁶]¦Qṭ|Ṛṇẹm⁵ØKƈBNɦÇȯ¢ṣḟPṇMʠ¬YėĊÇẒỊĿXJÑḷÞeȮȮɼ$ỴœeṂṠɲẓḊ⁺ċŻ⁽⁶Ẓ⁹<>#nẇṬ⁴\¤ÐṡḞF5ƙẇwḶȤYḍ¡¢~ṚⱮ-ṃƲ⁻Ṙ6ɱṬ?İẆḌỊþEØ»Ḳµe€ØẹIkḣ3)Z;€“squ“qu”$1¦
“ئµ£‘ḃ3$Xµ³Ð¡ḊFµ⁺wØ2$¿ịÇX€Fß¹Ñ?

Try it online!

A full program that takes a single argument, the number of syllables required.

Explanation

The core of this is a 66-word compressed dictionary string. If the words are split into groups of consonants and vowels and the first 3 groups taken for each word, they generate the desired starting, vowel and end groups from the question. The exceptions are qu and squ because they have a vowel in, so these are added manually. The word list was built algorithmically from the Jelly dictionary using a Python script. Note some letter groups are repeated, but the question allows the outputs to not uniformly represent each possible combination. If this were preferred, it would be straightforward to make each group unique at the cost of two bytes (Q€).

Helper link 1: check whether more than 3 vowels in a row or more than 3 of the same letter in a row
                | Sample input: branggag
e€Øẹ            | For each letter, is it a vowel? [0, 0, 1, 0, 0, 0, 1, 0]
    Œr          | Run-length encode [[0, 2], [1, 1], [0, 3], [1, 1], [0, 1]]
      ḢƇ        | Filter only those with true first value, popping first value [[1], [1]]
        ,       | Pair with
         Œɠ     | Run lengths of input [[[1], [1]], [1, 1, 1, 1, 2, 1, 1]
           F    | Flatten [1, 1, 1, 1, 1, 1, 2, 1, 1]
            >2  | Greater than 2 [0, 0, 0, 0, 0, 0, 0, 0, 0]
              Ẹ | Any 0
Helper link 2: The three groups of strings
“yŒʠ...þEØ»                          | Compressed string: shmooze gaolbird hailshot shriech waeful furze ghaut cruelness stealthier gneiss shoeshine wheelchair wring build priorship knosp spoilfive karst through coalpit teschenite schoolkid theurgic zabtieh skiamachies yirth snazzier slimnastics scripted smirch droskies strift blepharism chaulmoogra glegness scarf fratch clerk brank jarvey flourless vorpal grex nard plumb larn philter sorbo tractabilities parcel mart damp rearm back bast bag bant baba boll bad bap becap basal ban bail bare
           Ḳ                         | Split at spaces
            µ        )               | For each word: e.g. hailshot
             e€Øẹ                    |   Check whether each character is a vowel [0, 1, 1, 0, 0, 0, 1, 0]
                 I                   | Increments of this [1, 0, -1, 0, 0, 1, -1]
                  k                  |   Split word at truthy values of this [h, ai, lsh, o, t]
                   ḣ3                |   Take the first three [h, ai, lsh]
                      Z              | Transpose (so now have three lists, start consonants, vowels, end consonants)
                        €        $1¦ | For the first group
                       ; “squ“qu”    | Append squ and qu
Main link
          µ³Ð¡                     | Repeat the following the input number of times, collecting results:
“ئµ£‘                             |   18, 5, 9, 2
      ḃ3$                          |   bijective base 3: [1,2,3],[1,2],[2,3],[2]
         X                         |   Take one at random
              Ḋ                    | Remove first item (which will be the input to the link because if the way С works
               F                   | Flatten; we now have e.g. [1,2,3,2,3,1,2,3,2]. This corresponds to SC V EC V EC AC V EC V
                µ⁺    ¿            | Do everything so far once and then repeat while:
                  wØ2$             |   The output contains two twos (i.e. vowel-vowel)
                       ịÇ          | Look these up in the previous link, so we now have a group of letter groups for each position
                         X€F       | Pick a random letter group for each position
                            ß¹Ñ?   | If helper link 1 is true, retry the whole of this link again. Otherwise implicitly output

Nick Kennedy

Posted 2019-04-22T23:38:54.407

Reputation: 11 829

1Curious to see the explanation, but are you sure it's correct? I get an output gnuignaalfbi for input 4, but aa shouldn't be possible if I understood the challenge correctly. The section combining syllables states "..., however you cannot place a syllable ending with a vowel immediately before one starting with a vowel." – Kevin Cruijssen – 2019-04-24T07:31:53.707

@KevinCruijssen missed that. Should now meet that requirement too. Thanks for pointing out – Nick Kennedy – 2019-04-24T08:29:02.813

1Nice answer, I like the dictionary strings you've used to make all the groups. Although I'm not sure why Jelly's dictionary contains words like shmooze gaolbird hailshot shriech waeful furze ghaut, haha. xD How large is Jelly's dictionary anyway? – Kevin Cruijssen – 2019-04-25T07:21:21.310

1@KevinCruijssen Large. There are 20453 words of less than 6 letters and 227845 large words. – Nick Kennedy – 2019-04-25T19:34:40.013

0

Python 2, 522 510 bytes

from random import*
import re
c=choice
S,V,E=[map(str.lower,re.findall('[A-Z][a-z]*',x))for x in'BCDFGHJKLMNPRSTVWYZBlBrChClCrDrFlFrGhGlGnGrKnPhPlPrQuScShSkSlSmSnSpStThTrWhWrSchScrShmShrSquStrThr','AeAiAoAuEaEeEiEuIaIeIoOaOeOiOoOuUeUiAEIOU','BCDFGLMNPRSTXZBtChCkCtFtGhGnLbLdLfLkLlLmLnLpLtMbMnMpNkNgNtPhPtRbRcRdRfRgRkRlRmRnRpRtRvRzShSkSpSsStZzLchLshLthRchRshRstRthSchTch']
def f(n):w=c(['',c(S)]);exec"e=c(E);w+=c(V)[-(w[-1:]in V):]+c([c(S),e,e+c([x for x in S if x[0]*2!=e])])*(n>1);n-=1;"*n;return w+c(['',e])

Try it online!

TFeld

Posted 2019-04-22T23:38:54.407

Reputation: 19 246

0

Pyth, 346 335 bytes

McG.u+NYr9,VHSlH1smjOgs@L"eaiou"jC" ¤E̽]¢¨¦l#"5,4 17*Vd,Og"bcdfghjklmnprstvwyzblbrchclcrdrflfrghglgngrknphplprquscshskslsmsnspstthtrwhwrschscrshmshrsqustrthr"[18 29 6)Og"bcdfglmnprstxzbtchckctftghgnlbldlflklllmlnlpltmbmnmpnkngntphptrbrcrdrfrgrkrlrmrnrprtrvrzshskspssstzzlchlshlthrchrshrstrthschtch"[13 43 8)tuaGO<W!eeG^,1Z2 2Q]1

Try it online here.

Sok

Posted 2019-04-22T23:38:54.407

Reputation: 5 592

0

Ruby, 381 379 375 bytes

Uses messy regex matches to get the consonant groups. Could probably be optimized.

->n,w=?a..s='zzz',a=[1]{s=(1..n).map{a=[w.grep(/^([^aeiouq]|[bcfgp][lr]|s?ch|dr|gn|kn|ph|s?qu|s[ct]r?|sh[mr]?|th?r?|s[klmnp]|wh|wr|gh)$/)+(a[-1]?[p]:[]),w.grep(/^[aeiou]{,2}$/),w.grep(/^([^aeiouqhjkvwy]|[bcflnprs]t|ck|gh|gn|l[bdfk-np]|m[bnp]|nk|ng|ph|r[bcdfgk-npvz]|[lr]?[stc]h|s[kps]|zz|rst|[st]ch)$/)<<p].map(&:sample)}*''while s=~/[aeiou]{3}|(.)\1\1|aa|eo|ii|iu|u[aou]/;s}

Try it online!

Value Ink

Posted 2019-04-22T23:38:54.407

Reputation: 10 608