Garble that string!

20

2

Given a string as input, output one or more variants of the string such that:

  • No character is in it's original position
  • No character is adjacent to a character that it was originally adjacent to

You can assume this will always be possible for the given string, and will only contain single case alphabetical characters ([a-z] or [A-Z] if you prefer)

Note that duplicates of the same character are not considered unique.

For example, given the input programming, the output cannot contain an m at the 7th or 8th character, and cannot contain a g at the 4th or 11th character (1 indexed)

Example:

Take the string abcdef

The following would be a valid output: daecfb

However the following would be invalid: fdbcae as in this example c and b are still adjacent.

Adjacency also wraps, meaning you could not do fdbeca as f and a are still adjacent.

Testcases:

Note these are not the only valid outputs for the given inputs

Written as input -> output:

helowi -> ioewhl
mayube -> euabmy
stephens -> nhseespt
aabcdeffghij -> dbfhjfigaeca

Scoring:

This is so fewest bytes in each language wins!

Skidsdev

Posted 2017-06-08T15:14:13.397

Reputation: 9 656

No character is adjacent to a character that it was originally adjacent to. Does order not matter for adjacency? So input "abcd" cannot have "ab" anywhere, and cannot have "ba" anywhere either? – DrZ214 – 2017-06-09T07:03:19.867

@DrZ214 that is correct – Skidsdev – 2017-06-09T08:00:25.217

Answers

5

Jelly, 24 23 bytes

ẋ2ṡ2Ṣ€
dzǤœ&¬ɓ³=Sȯ
ẊÇ¿

Try it online!

Extremely long by virtue of my being awful at Jelly, but it finally works, at least... still in the process of golfing.

link that generates a list of sorted adjacent pairs:
ẋ2            duplicate argument ("abc" -> "abcabc")
  ṡ2          slices of 2 (-> "ab","bc","ca","ab","bc")
    Ṣ€        sort each

link that tests for invalid permutations:
Ç             get sorted adjacent pairs of argument
 ³Ç¤          do the same for the original input
    œ&        set intersection, then...
      ¬       ...inverse; i.e. do they have no elements in common
       ɓ   ȯ  logical OR the result of that with...
        ³=    elementwise equality with original input, and...
          S   ...sum; i.e. are some characters in the same position

main link:
Ẋ             shuffle the input list
  ¿           while
 Ç            the result of the previous link is truthy

Doorknob

Posted 2017-06-08T15:14:13.397

Reputation: 68 138

Tested with all testcases in OP, works for all of them – Skidsdev – 2017-06-08T16:25:13.127

This might be really long for Jelly, but its extremely short for everything else (with the possible exception of 05AB1E, and a few other insane golfing languages.) – Gryphon – 2017-06-08T16:33:16.350

yeah it's insanely short, I didn't expect even Jelly to do it this golfily, even 05AB1E's wrong solution that didn't check original char position was 45 bytes – Skidsdev – 2017-06-08T16:34:24.800

There goes another mod, corrupted by Jelly. How sad. – caird coinheringaahing – 2017-06-08T23:00:42.153

3

PHP>=7.1, 147 Bytes

for($a=$argn,$r="^$a[-1].*$a[0]$",$k=0;$v=$a[$k];)$r.="|^.{{$k}}$v|$v".($l=$a[$k++-1])."|$l$v";for(;preg_match("#$r#",$s=str_shuffle($a)););echo$s;

PHP Sandbox Online

PHP>=7.1, 184 Bytes

Use the levenshtein distance instead of a Regex way

for($a=$argn;$v=$a[$k];$r[]=$l.$v)$r[]=$v.($l=$a[$k++-1]);for(;!$t&&$s=str_shuffle($a);)for($t=1,$i=0;$v=$s[$i];$t*=$v!=$a[$i++])foreach($r as$x)$t*=levenshtein($x,$s[$i-1].$v);echo$s;

PHP Sandbox Online

PHP, 217 bytes

Version under 7.1

for($l=strlen($a=$argn),$r=$a[$k=0].$a[$l-1]."|".$a[$l-1]."$a[0]|^{$a[$l-1]}.*$a[0]$";$v=$a[$k];!$k?:$r.="|$v".$a[$k-1],++$k<$l?$r.="|$v".$a[$k]:0)$r.="|^.{{$k}}$v";for(;preg_match("#$r#",$s=str_shuffle($a)););echo$s;

Try it online!

Jörg Hülsermann

Posted 2017-06-08T15:14:13.397

Reputation: 13 026

*Oh my god it works* – Skidsdev – 2017-06-08T16:12:31.070

Why should it not work? I make every possible regex. If it match shuffle the string till it not match – Jörg Hülsermann – 2017-06-08T16:14:20.423

wait, fails on helowi, outputs ioewlh, i and h are adjacent – Skidsdev – 2017-06-08T16:14:53.793

@Mayube Okay that should now make the last case safe – Jörg Hülsermann – 2017-06-08T16:21:43.993

Yup, tested with all testcases in the OP, they all work – Skidsdev – 2017-06-08T16:23:22.203

++$k<$l saves 3 bytes. With PHP 7.1, $l can be rendered obsolete (if you check $a[++$k] instead of ++$k<$l); that should save 16 bytes. – Titus – 2017-06-08T17:41:46.030

3

Python 2, 185 bytes

from itertools import*
x=input()
g=lambda m:set(zip(m*2,(m*2)[1:]))
for l in permutations(x):
 if not((g(l)|g(l[::-1]))&(g(x)|g(x[::-1]))or any(a==b for a,b in zip(x,l))):print`l`[2::5]

Try it online!
Prints all valid strings

Rod

Posted 2017-06-08T15:14:13.397

Reputation: 17 588

tested for mayube, stephens and helowi, seems to work for all 3. I need to make an output validator to do some more intensive testing though – Skidsdev – 2017-06-08T16:17:46.157

Timed out for aabcdeffghij, but that doesn't mean it doesn't work, just that it takes longer than a minute for that input – Skidsdev – 2017-06-08T16:20:52.353

It takes a LONG time to run "aabcdeffghij" on my machine. So far >2min. Also looks like this prints more than one permutation, which is not according to spec. – Not that Charles – 2017-06-08T17:06:49.983

Rod - You may save some bytes with print next(l for l in permutations(x) if not((g(l)|g(l[::-1]))&(g(x)|g(x[::-1]))or any(a==b for a,b in zip(x,l)))) – Not that Charles – 2017-06-08T17:08:56.013

@NotthatCharles you forgot the \l`[2::5]` =/ – Rod – 2017-06-08T17:36:39.903

i can't count... – Not that Charles – 2017-06-08T17:49:22.553

3

Brachylog, 21 bytes

p.jP;?z≠ᵐ&j¬{s₂p~s}P∧

Try it online!

Explanation

I really would have wanted for p.;?z≠ᵐ&j¬{s₂p~s~j} to work for 2 bytes less, but it seems ~j is not smart enough...

p.jP;?z≠ᵐ&j¬{s₂p~s}P∧  Input is a string, say ? = "asdfgha"
p                      Take a permutation of ?, say "sfagadh".
 .                     It is the output.
  j                    Concatenate it to itself: "sfagadhsfagadh"
   P                   Call that string P.
    ;?                 Pair P with the input: ["sfagadhsfagadh","asdfgha"]
      z                Zip, repeating elements of the longer string:
                        [["s","a"],["f","s"],["a","d"],...,["a","g"],["d","h"],["h","a"]]
       ≠ᵐ              Each pair must have different elements.
         &             Start new predicate
          j            Concatenate ? to itself: "asdfghaasdfgha"
           ¬{     }    The following cannot be satisfied:
             s₂        Take a substring of length 2
               p       and permute it.
                ~s     It is a substring of
                   P   P.
                    ∧  Do not unify P with the output.

Zgarb

Posted 2017-06-08T15:14:13.397

Reputation: 39 083

2

PHP 7.1, 136 131 bytes

inspired by Jörg´s solution:

for($a=$argn;$c=$a[$k];)$r.="|$c".($d=$a[$k-1])."|$d$c|^.{".+$k++."}$c";while(preg_match("#$a$r#",($s=str_shuffle($a)).$s));echo$s;

Run as pipe with -r or test it online. (Make sure that PHP version 7.1 or above is selected)

Requires PHP 7.1; add 14 bytes for older PHP: Replace $k-1 with ($k?:strlen($a))-1;
(two more bytes for PHP<5.3: $k?$k-1:strlen($a)-1)

breakdown

# A: loop through input to collect sub-expressions
for($a=$argn;$c=$a[$k];)
    $r.="|$c".($d=$a[$k-1])     # 1. pair of characters
        ."|$d$c"                # 2. reversed pair
        ."|^.{".+$k++."}$c";    # 3. $c is at k-th position
# B: shuffle input until regex does not match the result
while(preg_match("#$a$r#",($s=str_shuffle($a)).$s));    # (input as dummy sub-expression)
# C: print result
echo$s;

Titus

Posted 2017-06-08T15:14:13.397

Reputation: 13 814

@JörgHülsermann a lot more ;) – Titus – 2017-06-08T18:21:27.640

@JörgHülsermann The wrapping case is handled in the first iteration ($c=$a[$k=0], $d=$a[$k-1]) via $s.$s. – Titus – 2017-06-08T22:37:00.743

Okay nice trick – Jörg Hülsermann – 2017-06-08T23:00:19.167

1

PHP 7.1, 187 185 172 178 143 bytes

do for($r=str_shuffle($s=$argn),$p=$i=0;$c=$s[$i];$p+=($c==$z)+preg_match("#$a|$b#",$s.$s))$b=strrev($a=$r[$i-1].$z=$r[$i++]);while($p);echo$r;

Run as pipe with -r or test it online. (Make sure that PHP version 7.1.0 or above is selected!)

breakdown

do
    for($r=str_shuffle($s=$argn),   # 2. shuffle input
        $p=$i=0;$c=$s[$i];          # 3. loop through input
        $p+=($c==$z)                        # 2. set $p if char is at old position
            +preg_match("#$a|$b#",$s.$s)    #    or if adjacency occurs in input
    )
        $b=strrev($a=$r[$i-1].$z=$r[$i++]); # 1. concat current with previous character
while($p);                          # 1. loop until $p is falsy
echo$r;                             # 4. print

Titus

Posted 2017-06-08T15:14:13.397

Reputation: 13 814

Fails on input mayube, outputs yeuamb, m and a are adjacent – Skidsdev – 2017-06-08T16:00:25.883

1Also your online tester doesn't seem to be very good, every testcase I've tried just timesout after 3 seconds – Skidsdev – 2017-06-08T16:03:10.510

@Mayube I forgot to mention: Use PHP version 7.1 – Titus – 2017-06-08T16:22:31.890

1

Ruby, 110 97 102 bytes

->s{x=s.chars
t=s*2
x.shuffle!while s.size.times.any?{|i|a,b=(x*2)[i,2];a==s[i]||t[a+b]||t[b+a]}
x*''}

Try it online!

daniero

Posted 2017-06-08T15:14:13.397

Reputation: 17 193

This does not follow the rule of "wrapping" adjacency; for example, I got 3594817062 as an output on your TIO link. – Doorknob – 2017-06-08T21:21:03.470

@Doorknob fixed! – daniero – 2017-06-09T19:59:40.917

1

JavaScript 6, 116 Bytes

f=x=>(h=[...x].sort(_=>Math.random(z=0)-.5)).some(y=>y==x[z]||(x+x).match(y+(q=h[++z]||h[0])+'|'+q+y))?f(x):h.join``

f=x=>(h=[...x].sort(_=>Math.random(z=0)-.5)).some(y=>y==x[z]||(x+x).match(y+(q=h[++z]||h[0])+'|'+q+y))?f(x):h.join``

console.log (f('abcdef'));

l4m2

Posted 2017-06-08T15:14:13.397

Reputation: 5 985

1

Stax, 23 21 bytes

å╘┤‼¬½P¥ë└w↕⌐î◘E{╟u!Ö

Run and debug online!

Thanks for @recursive for saving 2 bytes.

Takes a very long time to run. A more reasonable/feasible version is (just 2 bytes longer)

Ç≡╨áiS║çdèû.#-Gî☺└╨◙σφ+

Run and debug online!

Explanation

Uses the unpacked version to explain.

w|Nc_:=nGyG|*{E-!f+}ch+2B
w                            Loop anything before `}` while
 |N                          Next permutation (starting from the input)
   c_:=                      Index where the current array has the same element as the input (*)
                   }ch+2B    Define a block that finds all contiguous pairs in current string, including the pair `[last element, first element]`
       nG                    Apply the defined block to current string                         
         yG                  Do the same for the input
           |*                Outer product, contains pairs (which themselves are pairs) constructed from the last two array.
             {   f           Only keep pairs
              E-!            whose two elements have the same set of characters
                  +          Prepend the array at step (*).
                             This is used as the condition for the while loop

Weijun Zhou

Posted 2017-06-08T15:14:13.397

Reputation: 3 396

Nice. There's an improvement you can make using G. You are doing {...}X!...x! to execute the same block twice. In general, you can rewrite this as G...G with }... at the end of the program, like this.

– recursive – 2018-03-09T02:45:32.537

Thank you. I have seen you used G in another post to save one byte by replacing {...}* with D.... I guess am just still not quite used to it ... – Weijun Zhou – 2018-03-09T03:00:28.767