24
\$\begingroup\$

How strings are twisted

The twisting algorithm is very simple. Each column is shifted down by its index (col 0 moves down 0, col 1 moves 1, ...). The column shift wraps to the top. It works like this:

aaaa
bbbb
cccc

Becomes:

a
ba
cba
----
 cba
  cb
   c

With everything under the line wrapping to the top. Real example:

Original:
\\\\\\\\\\\\
............
............
............

Twisted:
\...\...\...
.\...\...\..
..\...\...\.
...\...\...\

Input

Input is either an array of strings, or a multi-line string. All lines have the same length.

Output

The twisted string, multi-line output to std-out (or closest alternative).

Examples:

(> denotes input, trailing space is important)

>Hello, world!
>I am another 
>string to be 
>twisted!     

Hwrmoe oo br!
Ieii ,dttr e 
s lsna !ohl  
ttaltgnw  ed 


>\\\\\\\\\\\\
>............
>............
>............

\...\...\...
.\...\...\..
..\...\...\.
...\...\...\


>abcdefg
>.......

a.c.e.g
.b.d.f.


>abcdefghij
>..........
>..........

a..d..g..j
.b..e..h..
..c..f..i.


>\\\\.....././
>...../.......
>........././.
>..../.^\\....

\.........../
.\....^..../.
..\../.\../..
...\/...\/...

>cdeab
>deabc
>eabcd
>abcde

cbbbb
ddccc
eeedd
aaaae


>aeimquy37
>bfjnrvz48
>cgkosw159
>dhlptx260

ahknqx147
beloru258
cfipsvy69
dgjmtwz30


>abcdefghi
>jklmnopqr
>stuvwxyz1
>234567890

a3ume7yqi
jb4vnf8zr
skc5wog91
2tld6xph0
\$\endgroup\$
  • 12
    \$\begingroup\$ There better not be a Mathematica builtin for this. \$\endgroup\$ – Mama Fun Roll Feb 1 '16 at 16:38
  • 1
    \$\begingroup\$ Can we assume that the input will only contain ASCII? Or only printable ASCII + linefeeds or something? \$\endgroup\$ – Martin Ender Feb 1 '16 at 19:10
  • \$\begingroup\$ Yes, just ASCII and newline (unless you take input as an array). \$\endgroup\$ – J Atkin Feb 1 '16 at 19:22

19 Answers 19

3
\$\begingroup\$

Brachylog, 5 bytes

iᵇ↻₎ᵐ

Try it online!

Gets input as an array of columns (which seems to be within the question's specifications).

iᵇ - For each element in the array, pair it with its (0-based) index
- map this predicate to each element of the result:
↻₎ - permute (the column) circularly by the amount specified as the last element (the index)

Easily extended to a version that accepts a single multiline string:

13 bytes

ṇẹ\iᵇ↻₎ᵐ\cᵐ~ṇ

Try it online!

\$\endgroup\$
  • \$\begingroup\$ This is amazing information compression. \$\endgroup\$ – J Atkin Oct 27 '18 at 15:50
7
\$\begingroup\$

Pyth, 11

jC.>R~hZC.z

Try it here

jC.>R~hZC.z    ##  implicit: .z = list of input split by lines
        C.z    ##  transpose .z to get columns
  .>R~hZ       ##  shift each column by it's index
               ##  equivalent to .e.>bk
jC             ##  transpose back and join by newlines
\$\endgroup\$
7
\$\begingroup\$

APL (Dyalog), 7 bytes

⊖⊖⊖⍨⍬⍋⍉

Requires ⎕io←0

Try it online!

⍬⍋⍉ gets the range from 0 to the number of columns
reverses vertically
⊖⊖⍨⍬⍋⍉ rotate (vertically) the (vertically) reversed input by 0,1..
reverse that, and return it.

\$\endgroup\$
6
\$\begingroup\$

Retina, 111 101 92 87 bytes

Byte count assumes ISO 8859-1 encoding.

(?<=((.))*)(?=(?<1>.*¶)*.*(?<=(?=(?<-2>.)*(.))(?<-1>.+¶)*.*(.(?<=^(?<-1>¶?.+)*))*)).
$3

Woo, solved it in a single regex substitution. :) (Chances are, there's a shorter solution by using several, but where's the fun in that...)

Try it online!

Explanation

This requires some basic knowledge of balancing groups. In short, .NET's regex flavour allows you to capture multiple times with a single group, pushing all captures onto a stack. That stack can also be popped from, which allows us to use it for counting things inside the regex.

(?<=((.))*)

This pushes one capture onto both groups 1 and 2 for each character in front of the match (in the current line). That is, it counts the horizontal position of the match.

The rest is in a lookahead:

(?=(?<1>.*¶)*.* [...] )

We match each line and also push it onto group 1, such that group 1 is now the sum of the horizontal and vertical position (where the latter is counted from the bottom). This essentially labels the diagonals of the grid with increasing values starting from the bottom left corner. That .* then just moves the engine's cursor to the end of the string.

We now switch into a lookbehind, which is matched from right to left in .NET:

(?<= [...] (.(?<=^(?<-1>¶?.+)*))*)

This will repeatedly pop exactly H captures from group 1 (where H is the height of the input). The purpose of that is to take the group modulo H. Afterwards, group 1 contains the row (counted from the bottom) from which to pick the new character in the current column.

(?=(?<-2>.)*(.))(?<-1>.+¶)*.*

Another lookbehind, again starting from the right. (?<-1>.+¶)*.+ now uses group 1 to find the row from which to pick the new character and then the lookahead finds the correct column using group 2.

The desired character is captured into group 3 and written back by the substitution.

\$\endgroup\$
  • \$\begingroup\$ Ah, reading Retina's source was nice and clear :) $+ looks useful... especially if you only want to do one substitution :^) \$\endgroup\$ – FryAmTheEggman Feb 1 '16 at 18:00
  • \$\begingroup\$ @FryAmTheEggman $+ is actually pretty useless... it's description on MSDN sounds a lot more useful than it is because it implies that (a)|(b) --> $+$+ would double all as and bs but instead it removes all as, because it just refers to the syntactically last group. That means it's just a way to avoid counting all groups if you're too lazy (like I was). For golfing it only saves bytes when you have more than 9 groups, which is probably quite rare to begin with. \$\endgroup\$ – Martin Ender Feb 1 '16 at 18:27
  • \$\begingroup\$ That is unfortunate... Perhaps retina could have a new replacement group type that would return the last non-empty match group? Anyway, thanks for the explanation! :) \$\endgroup\$ – FryAmTheEggman Feb 1 '16 at 18:55
  • \$\begingroup\$ @FryAmTheEggman It will (it's one of the things I had in mind when rewriting Regex.Replace for Retina, but I didn't get around to implementing it yet). \$\endgroup\$ – Martin Ender Feb 1 '16 at 19:05
4
\$\begingroup\$

CJam, 13 bytes

qN/zee::m>zN*

Test it here.

Explanation

q    e# Read all input.
N/   e# Split into lines.
z    e# Transpose to get an array of columns.
ee   e# Enumerate, pairing each column with its index.
::m> e# Map: fold: rotate (cyclically shifting each column by its index).
z    e# Transpose again.
N*   e# Join with linefeeds.
\$\endgroup\$
  • 2
    \$\begingroup\$ You can almost pronounce that source code. \$\endgroup\$ – mınxomaτ Feb 1 '16 at 17:12
4
\$\begingroup\$

TeaScript, 10 bytes

xHl@C(r╢tD

Thanks to TeaScript 3's extremely concise syntax, this is really short :D

Would be 1-byte shorter if Sigma loop weren't buggy

Try it online

Explanation

      // Implicit, x = input
xH    // Transpose input
l@    // Loop
 C(r╢   // Cycle column by index
        // `╢` exits loop
t    // Transpose
D    // Join on \n
\$\endgroup\$
3
\$\begingroup\$

Python 3, 164 bytes

Not the best answer by a long shot, but the first in Python...

s=list(zip(*open(0).readlines()))[:-1]
r=[[s[i][(j-i)%len(s[i])] for j in range(len(s[i]))] for i in range(len(s))]
print('\n'.join([''.join(l) for l in zip(*r)]))
\$\endgroup\$
  • 1
    \$\begingroup\$ You can save a handful of bytes by taking out the space which follows a ) or ] in most cases, for example ''.join(l)for l in.... is perfectly valid \$\endgroup\$ – wnnmaw Feb 1 '16 at 20:22
3
\$\begingroup\$

MATLAB, 92 36 bytes

s=bsxfun(@circshift,s,0:size(s,2)-1)

Assuming that the input string s is already in the form of a 2D char array/ matrix, e.g.

s = ['abcdefg';'.......'];
s = ['\\\\.....././';'...../.......';'........././.';'..../.^\\....'];

Explanation: iterate through the columns of the matrix. For each column perform a circular shift of its elements by the number of characters that equals the column index (-1 because of MATLAB indexing).

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

Brachylog, 96 bytes

$\:0{h_.|[M:I]hh:I{bh0,?h.|[C:I]h$)D,I-1=:Dr:2&.}C,I+1=J,Mb:J:1&:[C]rc.}$\{hA,[A]:"~s
"w,?b:3&;}

This expects a list of character codes strings as input and no output, e.g. brachylog_main([`aaaa`,`bbbb`,`cccc`],_).

That's one ridiculously long answer, and there's probably a much shorter way to do it.

Explanation

§ Main Predicate

$\:0{}$\{}                            § Create a list containing the transposed input and 0
                                      § Call sub-predicate 1 with this list as input
                                      § Transpose its output and pass it as input to
                                      § sub-predicate 3


§ Sub-predicate 1

h_.                                   § If the matrix is empty, output is empty list
   |                                  § Else
    [M:I]hh:I{}C,                     § Input is [M,I], call sub-predicate 2 with the first
                                      § line of M and I as input. Its output is C.
                 I+1=J,Mb:J:1&        § Call sub-predicate 1 with M minus the first line
                                      § and I+1 as input
                              :[C]rc. § Its output is appended after C, which is then
                                      § unified with the output of sub-predicate 1.


§ Sub-predicate 2

bh0,?h.                               § If the second element of the input list is 0,
                                      § output is the first element of the input
       |                              § Else
        [C:I]                         § Input is [C,I]
             h$)D,                    § Perform a circular permutation of C from left to
                                      § right (e.g. [a,b,c] => [c,a,b]) and unify it with D
                  I-1=:Dr:2&.         § Call sub-predicate 2 with D and I-1 as input, unify
                                      § its output with sub-predicate 2's output


§ Sub-predicate 3

hA,[A]:"~s\n"w,                       § Write the first line of the input as a char codes
                                      § string followed by a new line

               ?b:3&;                 § Call sub-predicate 3 with input minus the first
                                      § line. If it fails (empty input), terminate
\$\endgroup\$
2
\$\begingroup\$

JavaScript, 92 89 bytes

3 bytes off thanks @Neil.

s=>(z=s.split`
`).map((m,i)=>m.replace(/./g,(n,j)=>z[((l=z.length)*j+i-j)%l][j])).join`
`

f=s=>
    (z=s.split`\n`).map((m,i)=>
        m.replace(/./g,(n,j)=>
            z[((l=z.length)*j+i-j)%l][j]
        )
    ).join`\n`

Input.value = `abcdefghij
..........
..........`
textarea{display:block;width:250px;height:75px;}
<textarea id='Input'></textarea>
<button id='Run' onClick='Output.value=f(Input.value);'>Run</button>
<textarea id='Output'></textarea>

\$\endgroup\$
  • \$\begingroup\$ You can save 3 bytes using replace: m.replace(/./g,(n,j)=>z[((l=z.length)*j+i-j)%l][j]). \$\endgroup\$ – Neil Feb 1 '16 at 19:07
  • 1
    \$\begingroup\$ Indeed, the [...m].map( all the way to and including the first .join. \$\endgroup\$ – Neil Feb 1 '16 at 19:15
2
\$\begingroup\$

Python 2, 115 bytes

lambda s:'\n'.join("".join(s)for s in zip(*[k[-i%len(k):]+k[:-i%len(k)]for i,k in enumerate(zip(*s.split('\n')))]))

Thanks to the wonder of zip managed to get this down to one line. See it in action here.

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

MATL, 18 21 bytes

Zy2):"G@Z)@qYS]N$h

Input is of the form

['Hello, world!'; 'I am another '; 'string to be '; 'twisted!']

Try it online!

How it works:

Zy       % implicitly take input: 2D char array. Get its size
2)       % second element from size vector: number of columns, say n
:        % create vector [1,2,...,n]
"        % for each element k in that vector
  G      %   push input
  @      %   push k
  Z)     %   k-th column from input
  @qYS   %   circularly shift k-1 positions
]        % end for loop
N$h      % concatenate all stack contents horizontally
         % implicitly display
\$\endgroup\$
1
\$\begingroup\$

F#, 105 bytes

My first stab at it (only a \n character is required):

let m x y=(x%y+y)%y
let f(a:string[])=Array.mapi(fun i x->String.mapi(fun j _->a.[m(i-j)a.Length].[j])x)a

Usage:

f [| @"\\\\\\\\\\\\"
     "............"
     "............"
     "............" |]
\$\endgroup\$
  • \$\begingroup\$ I don't think I have seen F# before on PPCG. \$\endgroup\$ – J Atkin Feb 2 '16 at 14:07
1
\$\begingroup\$

JavaScript (ES6), 73 bytes

t=>t.replace(/./g,(_,i)=>t[(i+s*l-i%l*l)%s],l=t.search`
`+1,s=t.length+1)

Explanation

t=>
  t.replace(/./g,(_,i)=> // replace each character at index i
    t[                   // get the character at index:
      (i                 // start at i
        +s*l             // add s*l to ensure the result is always positive for %s
        -i%l*l           // move the index upwards the num of chars from start of the line
      )%s                // shift the index into the the range of s
    ],
    l=t.search`
`+1,                     // l = line length
    s=t.length+1         // s = input grid length (+1 for the missing newline at the end)
  )

Test

var solution = t=>t.replace(/./g,(_,i)=>t[(i+s*l-i%l*l)%s],l=t.search`
`+1,s=t.length+1)
<textarea id="input" rows="5" cols="40">\\\\.....././
...../.......
........././.
..../.^\\....</textarea><br>
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>

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

Japt, 29 bytes

Uy £XsV=(Y*Xl -Y %Xl)+X¯V}R y

Test it online!

How it works

Uy        // Transpose rows and columns in the input string.
£     }R  // Map each item X and index Y in the result, split at newlines, to:
Y*Xl -Y   //  Take Y times X.length and subtract Y.
%Xl)      //  Modulate the result by X.length.
XsV=      //  Set V to the result of this, and slice off the first V chars of X.
+X¯V      //  Concatenate this with the first V chars of X.
y         // Transpose the result again.
          // Implicit: output last expression
\$\endgroup\$
1
\$\begingroup\$

Haskell, 81 bytes

let t=transpose in t.snd.mapAccumR(\c l -> 1+c,take(length l)(drop c$cycle l))0.t

reimplementation of the CJam example, though the reverse, map and enumerate is part of the mapAccumR, the snd removes the accumulator since we don't need it anymore, the reversal is just a side effect of the right fold.

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

Haskell, 65 bytes

g l@("":_)=l;g l|t<-tail<$>l=zipWith(:)(head<$>l)$g$last t:init t

Usage example: g ["1111","2222","3333"] -> ["1321","2132","3213"].

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

MATL, 9 bytes

"@X@qYS&h

Try it online!

Pretty similar in core to Luis Mendo's existing MATL answer, but shorter by using features that were probably not in the language at that point: 1. " iterates through a matrix's columns automatically now, so no costly business of constructing column indices and indexing into them (this is the biggie), 2. &h as a shorthand way of saying N$h, and 3. implicit loop end if ] is not specified.

Alternately, for the same bytecount:

tsn:ql&YS

Try it on MATL Online

      &YS   % circularly shift the matrix
     l      % across rows (i.e. shift each column) by the amounts
            %  given by this array:
tsn         % duplicate input, get the sum of each column, get the 
            %  number of elements in that (which is the number of columns)
   :q       % construct range 1 to ncols, then decrement to start at 0
            % (implicit output)
\$\endgroup\$
0
\$\begingroup\$

C (clang), 114 bytes

Works in GCC under MinGW. TIO's GCC gets confused by using strlen in the init expression of the first for loop.

f(L,n)char**L;{for(int l=strlen(*L),i=0,j,c;i<n;i++)for(j=c=0;j<=l;j++,c=c?c-1:n-1)putchar(l^j?L[(c+i)%n][j]:10);}

Try it online!

\$\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.