1
\$\begingroup\$

This question got me nostalgic: Build a word generator!

In the '80s I wrote a simple word generator in under 42kB (code and working memory) that would take a collection of strings and use them to create new words and phrases.

Your task is to recreate this program in as few bytes as possible, with a few minor updates.

Your program will take the input and ensure that there are two spaces after each sentence. Each sentence should end with a full-stop (.). There must not be three consecutive spaces anywhere in the text. Line breaks should be replaced by a single space. There should only be two spaces after a sentence and nowhere else.

Record the number of times each character triplet appears. If you're using regex to break up the text /\X/ is a good way to match a Unicode glyph (could be multiple codepoints, not necessarily a single codepoint). For the purposes of counting, assume that there are two spaces at the start of the text and two spaces at the end.

Hopefully, you now have some good data to work with! Randomly select a triplet where the first two characters are both spaces. For example, if the only two matching triplets are [' ', ' ', 'I'] => 3 and [' ', ' ', 'A'] => 7 there should be a 30% chance of selecting I and a 70% chance of selecting A. Shift the characters along and randomly select one of the next triplets. If A was the first character selected the next triplets might be [' ', 'A', 'n'] => 2, [' ', 'A', 't'] => 2 and [' ', 'A', 's'] => 3. Randomly select one using the correct weightings and so on. Repeat until the last two characters are both spaces, then output the string generated if it's 100 characters or longer. If the output is less than 100 characters, repeat the process again, adding to the existing string until it is at least 100 characters long.

You should end up with output something like below, which looks almost like the input language. As my test input I used the first chapter of Charles Dickens' A Tale of Two Cities but you can use any text you feel like. Please provide a link to your input text (preferably not copyrighted) and a sample of the output.

In harithe dir, in hadede Fards fouses, by we aws, mand by nouse St. Merty exce, he th at ing ithe inceir farce, a Capir bod day, one defor ond rodmane of the ce witsethe after seas a pleark parison a prion to eves hund Parglairty the beere tielaires, and wrece to ente comses itic plaw andozene hich tat andiver, a he pent wer thneople, the werseved froads se sebron theire mands inge Woodmage larestown ther Ligh, sed and was the withaved broce pers. Brity-fired of bust a din humakings th, incre pas of the amonoblis the a kne Chrooteres, to offle ound lies yeargland this thing by on the goil ituarivesdozen, moolurd instive the whe only a king was thelfe one divery. Und the intren a king thiging ors, and he tow, afty out pas musears, thot he in aces, it it Fran, tho the blets be anglaters ouseticiodmand whimeng was by the primed tord a ce a dirience.

TL;DR

Build sentences from test input by analysing the frequency of the character triplets, and using those frequencies to randomly select each character in sequence.

You can pre-format your text to make sure it matches the input requirements. It doesn't have to contribute to your byte-count.

If your language can't cope with Unicode at all, limit the input to ASCII characters. Ideally, your program should be able to cope with combining marks (accents and the like) if they are encoded separately but it doesn't have to. It shouldn't affect the output much, although it's possible you might get weird output in rare cases. e.g. if é is encoded as two codepoints, e+combining acute accent, it SHOULD (but doesn't HAVE to) treat it as a single glyph.

\$\endgroup\$
  • \$\begingroup\$ Could you include a TL;DR? \$\endgroup\$ – Leaky Nun May 1 '16 at 13:17
  • 5
    \$\begingroup\$ @KennyLau I could run the description through my program if that would help? \$\endgroup\$ – CJ Dennis May 1 '16 at 13:21
  • \$\begingroup\$ I'll try to understand the question xd \$\endgroup\$ – Leaky Nun May 1 '16 at 13:23
  • \$\begingroup\$ Could you not include characters spanning multiple bytes? \$\endgroup\$ – Leaky Nun May 1 '16 at 13:54
  • \$\begingroup\$ @KennyLau é could be one codepoint or two: an e with a combining acute accent. Ideally your program should keep the accent with the letter, if it happens to be encoded separately. That's what /\X/ does. For example in Sinhala ක is 1 codepoint, and ක් and කො are both 2 but /\X/ will match each of them as a single glyph. You probably won't get weird glyphs if your program treats them separately. \$\endgroup\$ – CJ Dennis May 1 '16 at 14:09
1
\$\begingroup\$

Ruby, 88 bytes

Port from the Python answer by @Blue with a few modifications because it's still the shortest way to do things in Ruby as well...

->s{o=e='  ';(s[x=rand(s.size-2),2]==o[-2,2]?o+=s[x+2]:0)while o.size<100||o[-2,2]!=e;o}

Alternate version using selection and sampling, 99 bytes

->s{o=e='  ';o+=s[(0..s.size-2).select{|i|s[i,2]==o[-2,2]}.sample+2]while o.size<100||o[-2,2]!=e;o}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I love your version with selection and sampling. “The mank becard of the spely, brick, fact, his lially whis thes, days leters thimplets lery and mosich at homeening, toon com feenthe hise alke loster towl acuse momessiome hed forbecafrood mad man’s retimplats give I’ven, exculy, of thaps hinfuld hime sted of therver parreters.” made my day. Next time I meet an English learner, he is going to have an amazing bedtime story in the strongest London accent possible. Or maybe one should make a video “How English language sounds to the rest of the world” for English speakers. \$\endgroup\$ – Andreï Kostyrka Aug 11 '16 at 11:55
0
\$\begingroup\$

Python 2.7, 156 149 135 131 bytes

Screw efficiency, as long as it's short.

Saved 7 bytes thanks to @TuukkaX on the import statement

Saved 14 bytes thanks to @KevinLau-notKenny for negative list indice trick and if statement.

Saved 4 bytes by changing the randint

Notice that the second level uses tabs, but SE renders as 4 spaces.

from random import*
def r(i):
 o='  '
 while len(o)<100or o[-2:]!='  ':
    x=randint(2,len(i))
    if i[x-2:x]==o[-2:]:o+=i[x]
 return o
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Why are you importing randint from the random? You can just use import random and then call random.randint. Am I missing something? \$\endgroup\$ – Yytsi Jun 10 '16 at 15:48
  • \$\begingroup\$ @TuukkaX You're right, I should be just doing import* so I don't have to say random twice \$\endgroup\$ – Blue Jun 10 '16 at 16:30
  • \$\begingroup\$ o[-2:] grabs the last two characters you need from the output string, saving bytes over o[l(o)-2:l(o)]. Also, the spec says you can stop when you have 100+ characters and the last two characters are spaces, which can cut down on your while condition to l(o)<100||o[-2]!=' ' \$\endgroup\$ – Value Ink Jun 10 '16 at 22:31
  • \$\begingroup\$ @KevinLau-notKenny order of operations says bitwise or won't work, but the rest will, thanks! \$\endgroup\$ – Blue Jun 11 '16 at 12:07
  • \$\begingroup\$ Erm, I typoed... the while check needs to be o[-2:]==' ', since the end condition is for the last two characters to both be spaces. whoops. (Also, SE is rendering the two spaces as one for some reason) \$\endgroup\$ – Value Ink Jun 12 '16 at 0:46
0
\$\begingroup\$

PowerShell, 141 bytes

param($d)$o='  '
while($o.Length-lt100-or$o.EndsWith('  ')){if(($s=$d[($x=Get-Random $d.Length)-2]+$d[$x-1])-eq$o[-2]+$o[-1]){$o+=$d[$x]}}$o

It's a port of @Blue's answer as well. Assuming pre-formatted text, as mentioned in the question.

e.g.

PS U:\posh> .\New-RandomStory.ps1 @'
  It was the best of times, it was the worst of times,
it was the age of wisdom, it was the age of foolishness,
it was the epoch of belief, it was the epoch of incredulity,
it was the season of Light, it was the season of Darkness,
it was the spring of hope, it was the winter of despair,
we had everything before us, we had nothing before us,
we were all going direct to Heaven, we were all going direct
the other way--in short, the period was so far like the present
period, that some of its noisiest authorities insisted on its
being received, for good or for evil, in the superlative degree
of comparison only.
'@

  It wincres the befor evil, its the all going redulight, fort, the of it we best waso forst waso fo
| improve this answer | |
\$\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.