10
\$\begingroup\$

In the absurdist play Rosencrantz and Guildenstern are Dead, the two main characters Rosencrantz and Guildenstern(or are they?) are always mixing up which of them is who—or sometimes which of their own body parts is which—because of a perceived lack of individual identity. Wouldn't it be absurd if they even shuffled around their names?

Your task it to write a function which takes in a string of an even length(and by design, a multiple of 4) that is greater than 7 characters, split it, and shuffle it.

The splitting shall be as follows: the string will be of format "abscd", with s acting as a seperator character. The first section and the separator, abs will be the first half of the string, whereas the second half will be cd

The length of a will be (string length / 4) - 1

The length of b will be (string length / 4)

The length of s will be 1

The length of c will be (string length / 4) + 1

The length of d will be (string length / 4) - 1

This may be really confusing, so let me show you with some examples

("a" + "bb" + "s" + "ccc" + "d").length //8
  1     2      1      3      1
|-------4--------|  |----4-----| <--- (4 is half of 8)

("rosen" + "crantz" + "&" + "guilden" + "stern").length  //24
    5         6        1        7          5

("foo" + "barr" + "?" + "barry" + "foo").length
   3       4       1      5         3

Finally:

You then shuffle the parts around, outputting adscb

ex. "rosencrantz&guildenstern" --> "rosenstern&guildencrantz"

"foobarr?barryfoo" --> "foofoo?barrybarr"

Rulez:

  1. Standard Loopholes are prohibited
  2. Acceptable answers: a function which takes input through one input string and returns one output string
  3. If the input string doesn't match the requirements provided above, your code MUST error out(doesn't matter what kind of Exception or Error)
  4. This is code-golf, so the shortest(valid)answer (in each language) wins!
  5. Bonus points for a one-liner :-) (Not really tho, just cool points)
\$\endgroup\$
12
  • 6
    \$\begingroup\$ Regarding your gangsta rulez: It is generally discouraged to favour "functions", as they are hard to define in general. Furthermore, handling invalid input is also mostly avoided, as it usually boils down to annoying boiler-plate code. \$\endgroup\$ Nov 3, 2018 at 19:44
  • \$\begingroup\$ @JonathanFrech I think the challenge of input validation is an interesting problem, as it can be handled a variety of ways from array traversal, to branching logic, to RegEx testing, so optimization of these can add a extra challenge ¯_(ツ)_/¯ I'll try that for another code golf challenge though :-) \$\endgroup\$
    – Michael
    Nov 3, 2018 at 19:47
  • 2
    \$\begingroup\$ tfw everyone is trying to get more flexible io methods to make the code in their favorite golfing lang. and tfw it happens on almost all questions \$\endgroup\$ Nov 3, 2018 at 19:58
  • 5
    \$\begingroup\$ Things to Avoid when writing challenges (Input Validation). \$\endgroup\$
    – Jo King
    Nov 3, 2018 at 20:22
  • 1
    \$\begingroup\$ @NathanMerrill It's mentioned in the spec that input has to be greater than 7 characters in length and its length must be divisible by four, Jo King was suggesting a test case entry of length 4 such "abcd" which should error out \$\endgroup\$
    – Thaufeki
    Nov 3, 2018 at 23:22

15 Answers 15

11
+500
\$\begingroup\$

K (oK), 35 34 33 bytes

{$[8>#x;.;<x!4!-&4#-1 0 2+-4!#x]}

Try it online!

Without input validation (for ngn's bounty), 25 24 23 bytes

{<x!4!-&4#-1 0 2+-4!#x}

Try it online!

Quickly learned a bit of K and, looking at the list of verbs, I thought an alternative approach (not using cut) could work here. And it worked perfectly.

How it works

{<x!4!-&4#-1 0 2+-4!#x}
                 -4!#x    Length divided by four (floor division)
        4#-1 0 2+         Generate lengths (x/4-1, x/4, x/4+2, x/4-1)
       &                  Generate that many 0, 1, 2, 3's
    4!-                   Negate and modulo 4; effectively swap 1 and 3
 <x!                      Sort the original string by above

{$[8>#x;.; <code> ]}  Input validation
 $[8>#x           ]   If the length is less than 8
        .             Dynamically generate an error
           <code>     Otherwise, run the main code
\$\endgroup\$
1
  • \$\begingroup\$ @ngn What happened to my eyes O.o \$\endgroup\$
    – Bubbler
    Nov 15, 2018 at 6:35
3
\$\begingroup\$

Perl 6, 60 58 bytes

-2 bytes thanks to Jo King

{[~] .rotor($_/4 X-1,0,+^-$_+>2,-1,1)[0,4,2,3,1;*]}o*.comb

Try it online!

Throws "Rotorizing sublist length is out of range" in case of error.

Explanation

{               # Anonymous block
 [~]            # Join
   .rotor(      # Split into sublists of specific length
     $_/4 X-    # Subtract from len/4
     1,
     0,
     +^-$_+>2,  # (len-1)>>2
                #   subtraction yields 1 if len is multiple of 4
                #   otherwise a value less than 1 causing an error
     -1,       
     1)
   [0,4,2,3,1;*]  # Rearrange sublists and take inner elements
}o*.comb          # Split into characters and feed into block
\$\endgroup\$
0
3
\$\begingroup\$

J, 36 35 bytes

5;@A.](<;.2~;)1<@{."+~1 0 _2 1-4%~#

Try it online!

-1 byte by {. + negative lengths & ;.2 which cuts on ones as "ending" markers instead.

Original answer, 36 bytes

5;@A.](<;.1~;)1<@{."+~_1 0 2 _1+4%~#

Try it online!

ngn mentioned "cut" on a comment to an earlier K answer, and it made me try J which has the same "cut" (I have no idea how K works).

How it works

5;@A.](<;.1~;)1<@{."+~_1 0 2 _1+4%~#  Monadic train.
                                4%~#  Length divided by four
                      _1 0 2 _1+      Generate the four segment lengths
              1<@{."+~  Generate [1 0 0...] boxed arrays of those lengths
      (     ;)          Raze; unbox and concatenate
     ] <;.1~            Cut the input string on ones as starting marker, then box each
5  A.  Rearrange the boxes in the order 0 3 2 1
 ;@    Raze again

Note that this function automatically handles invalid inputs:

  • If the input length is not a multiple of four, {. throws domain error since its length argument has to be integers.
  • If the input length is 4, the cut produces only two segments, and 5 A. throws index error.
  • If the input length is 0, the two arguments to cut don't have the same length, so length error is thrown.
\$\endgroup\$
3
\$\begingroup\$

Python 3, 103 102 101 97 88 86 84 bytes

def f(s):l=len(s);l//=4*(l%4<1<l/4);return s[:l-1]+s[1-l:]+s[2*l-1:1-l]+s[l-1:2*l-1]

Try it online!

Not really a one-liner, but ; is one less byte per line than linebreak and indent.

Throws ZeroDivisionError if input string length is less than 8 or not an integer multiple of 4.

Also works in Python 2.

-4 bytes thanks to Jo King

-9 bytes thanks to ovs

-2 bytes thanks to Jonathan Frech

-2 bytes thanks to Bubbler

\$\endgroup\$
5
  • \$\begingroup\$ @JoKing thanks for the tips, much appreciated :) \$\endgroup\$
    – Axim
    Nov 4, 2018 at 9:59
  • 1
    \$\begingroup\$ 88 bytes \$\endgroup\$
    – ovs
    Nov 4, 2018 at 11:56
  • \$\begingroup\$ @ovs nice catch on the adjacent indexes, as for the parens, I tried around for at least 20 minutes to see if I could get rid of some of them, then I completely missed that with the change to //= the outermost pair became redundant. Thanks a bunch! \$\endgroup\$
    – Axim
    Nov 4, 2018 at 13:05
  • 2
    \$\begingroup\$ -l+1 <-> 1-l? \$\endgroup\$ Nov 4, 2018 at 13:34
  • 1
    \$\begingroup\$ Merge the two inequalities to get to 84 bytes. \$\endgroup\$
    – Bubbler
    Nov 7, 2018 at 5:11
2
\$\begingroup\$

Perl 6, 78 bytes

*.comb[0..*/4-2,3* */4+1..*,*/2-1/(*>7)..3* */4,*/4-1/(*%%4)..*/2-2].flat.join

Try it online!

Anonymous code block that takes a string and returns the modified string if valid, else returns a division by zero error. I know I can modify an array directly, so I could swap the two sections of the string, but I can't quite figure it out.

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

K (ngn/k), 120 113 103 99 95 bytes

{$[(r>7)&0=4!r:#:x;{g:(s:*|(y*2)#x)\x;((y-1)#*g),((-y-1)#*|g),s,((y+1)#*|g),(-y)#*g}[x;r%4];l]}

Hopefully can be golfed down more, included an extra function for testing if string length is divisible by four, outputs error with reference to undeclared variable if input is invalid

EDIT: Missed condition on length greater than 7, included

EDIT: Combined into one function, removed redundant variable declarations

Try it online!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ this could be a lot shorter. do you know about "cut" (indices_string)? ping me in the orchard if i should explain it \$\endgroup\$
    – ngn
    Nov 5, 2018 at 18:25
  • 1
    \$\begingroup\$ i can do it in 34 bytes :) \$\endgroup\$
    – ngn
    Nov 5, 2018 at 18:52
  • \$\begingroup\$ I know about cut, but I didn't think about using it... 34 bytes?! I'm going to have to give this another go when I get home and see if I get near that \$\endgroup\$
    – Thaufeki
    Nov 5, 2018 at 21:28
  • \$\begingroup\$ i should mention: my solution doesn't make sure that invalid inputs (length<=7) cause an error \$\endgroup\$
    – ngn
    Nov 6, 2018 at 17:49
2
\$\begingroup\$

Ruby, 64 bytes

->s{a=s.size/4;s[1-a,a],s[a-1,a]=s[a-1,a],s[1-a,a];s[a*4]?1/0:s}

Try it online!

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

Retina 0.8.2, 58 or 73 or 83 or 93 bytes

((((.)))*?)(.(?<-2>.)+)(...(?<-3>.)+)((?<-4>.)+)$
$1$7$6$5

Try it online! Explanation:

((((.)))*?)

Capture a in $1, and make it as short as possible *?. $#2, $#3 and $#4 end up as the length of a.

(.(?<-2>.)+)

Capture b in $4. The (?<-2>.)+ captures up to the length of a, while the other . adds 1 to its length as required.

(...(?<-3>.)+)

Capture s and c in $6. Their combined length is three more than the length of a.

((?<-4>.)+)

Capture d in $7. Its length is no more than the length of a.

$

We made a as short as possible, but we still want to reach the end of the input.

$1$7$6$5

Exchange b and d.

The above stage does not validate its input. As Retina has no run-time errors, there are a number of options for input validation:

G`^(....){2,}$

Outputs nothing if the length is less than 8 or not a multiple of 4. (+15 bytes)

^(?!(....){2,}$).*
Error

Outputs Error if the length is less than 8 or not a multiple of 4. (+25 bytes)

+`^(....)*..?.?$|^(....)?$
.....$1

Hangs if the length is less than 8 or not a multiple of 4. (+35 bytes)

\$\endgroup\$
1
  • \$\begingroup\$ This doesn't throw an error on invalid inputs (as annoying as that is) \$\endgroup\$
    – Jo King
    Nov 3, 2018 at 22:42
1
\$\begingroup\$

C (gcc) with -Dx=memcpy and -DL=(l-1), 154 158 160 bytes

Returns NULL if the input string length is not divisible by 4 or shorter than 8 characters.

Thanks to Rogem and Jonathan Frech for the suggestions.

EDIT: Moved preprocessor defines to the command line and made the string dynamically-allocated to strictly conform with the puzzle.

f(s,t,l)char*s,*t;{l=strlen(s);l%4|l<8?t=0:(t=malloc(l+1),l/=4,x(t,s,L),x(t+L,s+3*l+1,L),x(t+2*L,s+L+l,l+2),x(t+3*l,s+L,l),t[4*l]=0);l=t;}//-Dx=memcpy -DL=(l-1)

Try it online!

\$\endgroup\$
6
  • \$\begingroup\$ Why t[80]? There does not seem to be an upper bound regarding input length. \$\endgroup\$ Nov 4, 2018 at 13:36
  • \$\begingroup\$ @JonathanFrech I did it to save bytes but you are correct. I've changed the solution to use malloc() instead. \$\endgroup\$
    – ErikF
    Nov 4, 2018 at 13:48
  • \$\begingroup\$ Returns by modification, return value is NULL for invalid output, uses return values from memcpy(), a function-like macro to skip the types and C99 variable-length arrays to skip malloc(). \$\endgroup\$
    – user77406
    Nov 5, 2018 at 9:36
  • \$\begingroup\$ Why 160 bytes, do you count the // or the -w? \$\endgroup\$
    – l4m2
    Nov 13, 2018 at 9:41
  • \$\begingroup\$ @l4m2 -w is just a convenience to suppress warnings (so errors are easier to find). I usually add command line arguments after a // to have TIO count their bytes for me, and then deduct 1 from the total to account for the one extra character needed to do that. \$\endgroup\$
    – user77406
    Nov 14, 2018 at 12:51
1
\$\begingroup\$

Jelly, 28 bytes

L7»4ḍİ×L:4;;ĖÄƲFÄœṖ⁸⁽%[D¤ị$F

(If a full program is allowed we can remove the trailing F)
If the length is less than 8 or not divisible by four a ValueError is raised during integer division of inf (a float) by 4 -- the division yields NaN (also a float) which then cannot be cast to an int.

Try it online!

How?

L7»4ḍİ×L:4;;ĖÄƲFÄœṖ⁸⁽%[D¤ị$F - Link: list of characters
L                            - length
 7                           - literal seven
  »                          - maximum (of length & 7)
   4ḍ                        - divisible by four? (yields 1 for good inputs; 0 otherwise)
     İ                       - inverse (1 yields 1; 0 yields inf)
      ×L                     - multiply by length (length or inf)
        :4                   - integer divide by 4 (errors given inf)
              Ʋ              - last four links as a monad (f(x)):
          ;                  -   concatenate -> [x,x]
            Ė                -   enumerate -> [1,x]
           ;                 -   concatenate -> [x,x,[1,x]]
             Ä               -   cumulative sum (vectorises at depth 1) -> [x,x,[1,1+x]]
               F             - flatten -> [x,x,1,1+x]
                Ä            - cumulative sum -> [x,2x,2x+1,3x+2]
                   ⁸         - chain's left argument (the input)
                 œṖ          - partition at indices (chops up as per requirements)
                          $  - last two links as a monad (f(z)):
                        ¤    -   nilad followed by link(s) as a nilad:
                    ⁽%[      -     10342
                       D     -     decimal digits -> [1,0,3,4,2]
                         ị   -   index into z (rearranges the pieces as per requirements)
                           F - flatten (back to a list of characters)
\$\endgroup\$
1
\$\begingroup\$

Jelly, 25 bytes

L:4’+“¡¢¢£¡‘Ṡ3¦ÄṬk⁸Ṛ2,5¦Ẏ

Try it online!

The can be removed to make this into a full program.

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

JavaScript (ES6), 97 89 bytes

Saved 8 bytes thanks to @l4m2

s=>(l=s.length/4)<2||l%1?Z:s.replace(eval(`/(.{${l}})(.{${l+2}})(.{${l-1}})$/`),'$3$2$1')

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 89B \$\endgroup\$
    – l4m2
    Nov 13, 2018 at 9:18
1
\$\begingroup\$

JavaScript (Node.js), 80 bytes

s=>(g=s.substr.bind(s))(0,l=s.length/4-1)+g(-l)+g(l-~l,l+3)+g(l,l+1,l<1==l%1||Z)

Try it online!

JavaScript (Node.js), 84 bytes

s=>(g=(a,b)=>s.substr(a,b))(0,l=s.length/4-1)+g(-l)+g(l-~l,l+3)+g(l,l+1,l<1==l%1||Z)

Try it online!

JavaScript (Node.js), 87 bytes

s=>(l=s.length/4)<2||l%1?Z:(g=(a,b)=>s.substr(a,b))(0,l-1)+g(1-l)+g(l+l-1,l+2)+g(l-1,l)

Try it online!

Shorter than RegExp

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

Java 8, 135 bytes

s->{int l=s.length();l=l>7&l%4<1?l/4:l/0;return s.substring(0,l-1)+s.substring(3*l+1)+s.substring(2*l-1,3*l+1)+s.substring(l-1,2*l-1);}

Throws ArithmeticException (divides by zero) if the input string does not match requirements. Try it online here.

Ungolfed:

s -> { // lambda function taking a String argument and returning a String
    int l = s.length(); // take the length of the input ...
    l = l > 7 &         // ... if it's  greater than 7 and ...
        l % 4 < 1       // ... a multiple of 4 ...
      ? l / 4           // ... divide by 4; otherwise ...
      : l / 0;          // ... error out (division by zero throws ArithmeticException)
    return // concatenate and return:
           s.substring(0, l - 1)             // a
         + s.substring(3 * l + 1)            // d
         + s.substring(2 * l - 1, 3 * l + 1) // sc
         + s.substring(l - 1, 2 * l - 1);    // b
}
\$\endgroup\$
1
  • \$\begingroup\$ Suggest l/=l>7&l%4<1?4:0; instead of l=l>7&l%4<1?l/4:l/0; \$\endgroup\$
    – ceilingcat
    Sep 20, 2019 at 2:02
0
\$\begingroup\$

C (gcc), 129 bytes

Returns by modification. Compile with:

-Df(s)=({char t[l=strlen(s)];l%4|l<8?0:(l/=4,x(t,s+l*2-1,l-~l),x(x(x(s+l*3,s+l-1,l)-l-2,t,l+2)-l+1,t+l+2,l-1),s);}) -Dx=memcpy

Source file:

l;

Try it online!

Degolf

-Df(s)=({ // Function-like macro f. Takes a char* as a parameter.
          // Return value is a pointer to s if successful, and to NULL if string was invalid.
     char t[l=strlen(s)]; // Allocate a local temp string.
     l%4|l<8?0: // Detect invalid strings. Return 0 (NULL) on invalid string.
         (l/=4, // We're only really concerned with floor(len/4), and this will yield that.
             memcpy(t,s+l*2-1,l-~l), // Copy the second half of chars to the temp storage.
             memcpy( // Because memcpy returns the address of the destination, we can chain
                     // the calls to save quite a few bytes, even after x->memcpy substitution.
                 memcpy(memcpy(s+l*3,s+l-1,l) // Next, copy the second quarter to the end.
                     -l-2,t,l+2) // After that, we copy back the third quarter to its place.
                          -l+1,t+l+2,l-1) // Finally, copy the fourth quarter to where the second
                                          // quarter was.
                      ,s);}) // And return the pointer.
\$\endgroup\$

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.