8
\$\begingroup\$

"Buzzing" Bill is a well respected beaver. He is the hardest working in his home dam. He was a strong beaver and was able to lift more logs than anyone at the dam. Unfortunately Buzzing Bill's career came to an end in a tragic accident. Being such a prominent figure in his town, the Beaver newspaper wanted to write a frontpage story remembering Buzzing Bill. However Beavers have much smaller newspapers than we do and can only fit 4 letters on each line. The newspaper is assigning you to the task of writing some code to output the four letter lines.

The objective: We need some code written that takes in a string as an input, ex: "Big Beaver Buzzing Bill Bite the Bullet" and splits it into four letter segments that can fit on the Beaver newspaper, and outputs the split segments in an array/list/structure

The answer to this question will have an output to the sentence above that looks much like this: [Big,Bea,ver,Buz,zing,Bill,Bite,the,Bul,let]

The output will complete the all of these criterion for beaver readability:

  1. Keeps 4 letter words or less together, and completely separate from other words, two words cannot occupy the same line— note that the first two indexes is not [BigB,eav]
  2. It splits words more than four letters and an even number of letters cleanly in two — i.e. do not have [Beav,er]
  3. Words with an 7 letters should split at the point between the first two identical adjacent consonants, where one consonant occupies the middle spot, if possible. “y” is not a consonant — Buzzing:[Buz,zing] instead of [Buzz,ing], additionally in very rare cases where the there is a triple consonant in the center, ex: “Wallled” would become [Wal,lled] as the split occurs at the first middle pair
  4. Words with an odd number of letters that do not satisfy rule #3 should be split so that the front of the word contains the extra letter — "Beavers" should be split as [Beav, ers] rather than [Bea,vers]
  5. Beavers are not very good at reading, so the newspaper will not use any words over 8 letters, and all words will be entirely lowercase letters(only the 26 used in English)

Make the Best of it Busy Beavers!

\$\endgroup\$
12
  • 3
    \$\begingroup\$ @KidWithComputer There's no rule establishing that two words can't share a line. If that's your intention, you might want to add one. \$\endgroup\$ Commented Aug 6, 2023 at 22:17
  • 1
    \$\begingroup\$ how shall we split wallled (to be led by a wall)? \$\endgroup\$
    – Adám
    Commented Aug 6, 2023 at 22:24
  • 1
    \$\begingroup\$ @UnrelatedString I edited the question accordingly to make it explicitly clear, and you are correct for the split of breeder \$\endgroup\$ Commented Aug 6, 2023 at 22:24
  • 2
    \$\begingroup\$ @Adám I edited many of the rules to accordingly, thank you, to clarify additionally, sayyids would become [sayy, ids], hypens will not be given as an input \$\endgroup\$ Commented Aug 6, 2023 at 22:28
  • 1
    \$\begingroup\$ Note that your example is not consistent anymore with the 5th rule (lowercase only). \$\endgroup\$
    – Arnauld
    Commented Aug 6, 2023 at 22:45

11 Answers 11

5
\$\begingroup\$

JavaScript (ES10), 100 bytes

Returns an array of strings.

s=>s.split` `.flatMap(s=>s[4]?[s.slice(0,q=s.length+!/^..([^aeiouy])\1../.test(s)>>1),s.slice(q)]:s)

Try it online!


JavaScript (ES6), 96 bytes

Returns a string with additional spaces.

s=>s.replace(/\S{5,}/g,s=>s.slice(0,q=s.length+!/^..([^aeiouy])\1../.test(s)>>1)+' '+s.slice(q))

Try it online!

\$\endgroup\$
0
3
\$\begingroup\$

Retina 0.8.2, 65 bytes

S` 
(..(..(?=....)|([^aeiouy])(?=\3...)|.(.(?=...))?))(..+)
$1¶$+

Try it online! Link includes test case. Explanation:

S` 

Split on spaces.

(..(..(?=....)|([^aeiouy])(?=\3...)|.(.(?=...))?))(..+)
$1¶$+

Split words of at least five letters in one of four ways:

  • eight letter words are split after four letters
  • seven letter words whose third letter is not a vowel and is doubled after three letters
  • other seven letter words after four letters
  • other words after three letters

$+ just saves me counting to find the group number of the last capture group.

\$\endgroup\$
3
\$\begingroup\$

Python 3.8 (pre-release), 261,265 232 bytes

gotta love the walrus. +4 bytes to fix rule 4.

import re
def f(s,q=[]):
 for w in s.split():
  if len(w)<5:q+=[w]
  elif(k:=len(w))%2<1:q+=[w[:k//2],w[k//2:]]
  elif b:=re.search(r'(?=[^aeiou])([a-z])\1',w):q+=[w[:(i:=b.end()-1)],w[i:]]
  else:l=k//2+1;q+=[w[:l],w[l:]]
 return q

Try it online!

\$\endgroup\$
5
  • 2
    \$\begingroup\$ It looks like you have repeated logic in the last 3 cases where you do q+=[w[:c],w[c:]] for some value c you compute. You can probably shorten your code by computing c within the if/elif/else but doing the append afterwards. \$\endgroup\$
    – xnor
    Commented Aug 7, 2023 at 20:12
  • 1
    \$\begingroup\$ Whittled it down to 145 (and fixed rule 3 handling) \$\endgroup\$ Commented Aug 7, 2023 at 21:47
  • 1
    \$\begingroup\$ *144 \$\endgroup\$ Commented Aug 7, 2023 at 22:06
  • 1
    \$\begingroup\$ actually I might just post this myself lol \$\endgroup\$ Commented Aug 7, 2023 at 22:07
  • 1
    \$\begingroup\$ go for it! thats awesome. Thanks to you both! \$\endgroup\$ Commented Aug 8, 2023 at 13:06
3
\$\begingroup\$

Python, 142 139 134 131 130 bytes

import re
for w in input().split():c=re.match(r'..([^aeiouy])\1...$',w)and 3or(w>w[:4])*len(w[::2]);c>0!=print(w[:c]);print(w[c:])

Attempt This Online!

-3 thanks to xnor one-lining it, with some comparison chaining on top to shave one byte off an and

-1 thanks to spooky_simon actually knowing how re.match works

Basically just a bunch of incremental golfs to spooky_simon's solution (inspired by xnor's comment, and with fixes to rule 3), but it's barely even recognizable anymore so I figured I may as well post it for myself.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ -3 bytes \$\endgroup\$
    – xnor
    Commented Aug 8, 2023 at 1:13
  • 1
    \$\begingroup\$ -3 bytes regex match starts at the beginning of the string so no need for end of line anchor \$\endgroup\$ Commented Aug 8, 2023 at 16:05
  • 1
    \$\begingroup\$ @spooky_simon Removing the end anchor splits bassline wrong (since the split is hardcoded at 3 instead of half the length), but removing the start anchor still works fine. Thanks! \$\endgroup\$ Commented Aug 8, 2023 at 22:33
  • \$\begingroup\$ Good catch with bassline, totally missed it! heres another -2 bytes for printing syntax \$\endgroup\$ Commented Aug 9, 2023 at 13:02
3
\$\begingroup\$

Scala, 200 147 bytes

Port of @Arnauld's Javascript answer in Scala.


   

Golfed version. Attempt this online!

Saved so many bytes thanks to the comments.

_.split(" ").flatMap(w=>if(w.size>4){val q=w.size+1-raw"..([^aeiouy])\1..".r.findAllIn(w).size;Seq(w.slice(0,q/2),w.slice(q/2,w.size))}else Seq(w))

Ungolfed version. Attempt this online!

import scala.util.matching.Regex

object Main {
  def main(args: Array[String]): Unit = {
    val s = "big beaver buzzing bill bite the bullet"
    println(splitAndManipulate(s))
  }

  def splitAndManipulate(s: String): List[String] = {
    s.split(" ").toList.flatMap(word => {
      if (word.length >= 5) {
        val regex: Regex = """..([^aeiouy])\1..""".r
        val q = if (regex.findFirstIn(word).isEmpty) {
          (word.length + 1) >> 1
        } else {
          word.length >> 1
        }
        List(word.slice(0, q), word.slice(q, word.length))
      } else List(word)
    })
  }
}
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Try it online - 196 bytes (both >>1 to /2, and removed two spaces). \$\endgroup\$ Commented Aug 8, 2023 at 9:25
  • \$\begingroup\$ Also >=5 can be >4 for another -1 byte, and you can probably save some more bytes creating a variable for w.length, since you use it four times? \$\endgroup\$ Commented Aug 8, 2023 at 9:48
  • \$\begingroup\$ Attempt this online 147 bytes. \$\endgroup\$
    – Kjetil S
    Commented Aug 8, 2023 at 10:11
  • \$\begingroup\$ -2 bytes: _ split " "flatMap \$\endgroup\$
    – corvus_192
    Commented Aug 10, 2023 at 15:59
2
\$\begingroup\$

Jelly, 29 26 bytes

Ḳµ3.ịfƒØYL×7=LạLH>2×ƊĊṬk)Ẏ

Try it online!

This... can probably still be better...

Ḳµ                      )     For each word:
      ƒ                       Reduce
  3.ị                         the third and fourth letters in the word
     f                        by intersection
       ØY                     starting with the list of all consonants.
         L                    Is the length of that result
          ×7                  times 7
            =L                equal to the length of the word?
              ạL              Decrement the length if so.
                H             Halve,
                 >2×Ɗ         zero if =< 2,
                     Ċ        ceil,
                      Ṭk      split after that index.
                         Ẏ    Flatten the splits together.
\$\endgroup\$
3
  • \$\begingroup\$ Awesome work so far, however Asset does not split into as set correctly \$\endgroup\$ Commented Aug 7, 2023 at 0:24
  • \$\begingroup\$ @KidWithComputer Doesn't rule 3 only apply to 7-letter words...? I included "asset" specifically to test that. \$\endgroup\$ Commented Aug 7, 2023 at 0:26
  • \$\begingroup\$ Oh your so right! My mistake! \$\endgroup\$ Commented Aug 7, 2023 at 0:29
2
\$\begingroup\$

Python 3, 379 bytes

I got kinda lazy at the end after banging my head against this problem for a couple hours. Since I wasn't sure if I could use built-in modules like itertools I decided not to test my luck and just make a function (which came out kinda bulky)

Here's my solution

def f(l):
    if type(l) in [list,tuple]:
        for s in l:
            yield from f(s)
    else:yield l
b=lambda s:list(f([[w[p:p+(len(w)//2)]for p in range(0,len(w),len(w)//2)]if(len(w)>4 and len(w)%2==0)else(([(w[:a],w[a:])for a in[{1:4,**{1:a for a in[i+1 for i,(a,b)in enumerate(zip(w,w[1:]))if a==b and a not in"aeiouy"]}}[1]]])if len(w)==7 else w) for w in s.split()]))

Was I a bit smarter and managed to remove the function I could've saved about 100 bytes, but oh well...

\$\endgroup\$
4
  • 1
    \$\begingroup\$ you have like 20 bytes of white space in your function f, easy to shave it down for some freebies. Additionally, using codegolf.stackexchange.com/a/107311/118465 can save maybe 10 bytes on the type checking... \$\endgroup\$ Commented Aug 7, 2023 at 14:19
  • 3
    \$\begingroup\$ thanks! those tips on type checking seem really useful. as for the whitespace in f, i coded this on my phone while i was having breakfast and i forgot i could do that... :') \$\endgroup\$ Commented Aug 7, 2023 at 14:46
  • 1
    \$\begingroup\$ the yield from is very very cool, never seen it before, so thanks as well! \$\endgroup\$ Commented Aug 7, 2023 at 14:54
  • 1
    \$\begingroup\$ "i coded this on my phone while i was having breakfast" -Legendary \$\endgroup\$ Commented Aug 15, 2023 at 22:23
2
\$\begingroup\$

Charcoal, 46 bytes

F⪪S ¿∧⁼Lι⁷›⁼§ι²§ι³№aeiouy§ι²⟦…ι³✂ι³⟧⪪ι⁻⁴⊘&²⊕Lι

Try it online! Link is to verbose version of code. Explanation:

F⪪S 

Split the input on spaces and loop over the words.

¿∧⁼Lι⁷›⁼§ι²§ι³№aeiouy§ι²

Check to see whether this is a seven-letter word with third and fourth letters both the same consonant.

⟦…ι³✂ι³⟧

If so then split it after three letters.

⪪ι⁻⁴⊘&²⊕Lι

Otherwise split it after a number of letters given by a formula which results in splits of 3, 3, 4, 4, 3, 3, 4, 4 for words of length 1 to 8, which is the desired result.

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

05AB1E, 31 bytes

#εDg©4›i2ä®7Qi¬γθžPÃg2@iJ34S£]˜

Try it online.

Explanation:

#                      # Split the (implicit) input-string by spaces
 ε                     # Map over each word:
  Dg                   #  Duplicate the current word, then pop and push its length
    ©                  #  Store this length in variable `®` (without popping)
    4›i                #  If the length is larger than 4:
       2ä              #   Split the string into two 'equal-sized' parts, where the
                       #   first part is one character longer for odd-sized strings
         ®7Qi          #   If length `®` equals 7:
             ¬         #    Push the first part with four characters (without popping
                       #    the pair)
              γ        #    Group adjacent similar characters together
               θ       #    Pop and keep the last character-group
                žPÃ    #    Only keep the consonants of this group
             g2@i      #    If the length of what remains is >=2:
                 J     #     Join the pair back together to the original word
                  34S£ #     And split it into parts of sizes [3,4] (instead of the
                       #     [4,3] done by the `2ä`)
 ]                     # Close all three if-statements and the map
  ˜                    # Flatten the list
                       # (after which the result is output implicitly)
\$\endgroup\$
2
\$\begingroup\$

Ruby -an, 87 bytes

-an enables autosplitting on the implicit input, which is stored in $F.

The main strategy here is to abuse String#slice!, which removes the substring that matches the parameter from the original string and returns it, which means what remains can be returned as the second half. It can take as a parameter, among other things, a regex or a range, which means the 7-length case can be handled with a regex and everything else can be handled with a range.

puts$F.map{|f|s=f.size
s>4?[f.slice!(s==7?/..(([^aeiouy])(?=\2)|..)/:0...s/2+s%2),f]:f}

Attempt This Online!

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

Perl 5, 99 bytes

$_=join$",map/(..([^aeiouy]))(\2...$)|(.{3,4})(.{3,4})|(...)(..)/i?($1||$4||$6,$3||$5||$7):$_,split

Try it online!

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Doesn't seem to like the word missions. \$\endgroup\$
    – Neil
    Commented Aug 7, 2023 at 13:06
  • \$\begingroup\$ @Neil – good catch. Corrected. \$\endgroup\$
    – Kjetil S
    Commented Aug 7, 2023 at 14:11

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.